正则表达式只匹配大写"单词"和一些例外

Pat*_*ick 27 regex match uppercase

我有以下技术字符串:

"The thing P1 must connect to the J236 thing in the Foo position."
Run Code Online (Sandbox Code Playgroud)

我想用正则表达式匹配那些只有大写的单词(即here P1J236).问题是,当它是一个单字母的单词时,我不想匹配句子的第一个字母.

例如,在:

"A thing P1 must connect ..." 
Run Code Online (Sandbox Code Playgroud)

我只想P1,不是AP1.通过这样做,我知道我可以错过一个真正的"单词"(比如"X must connect to Y"),但我可以忍受它.

另外,如果句子全部为大写,我不想匹配大写单词.

例:

"THING P1 MUST CONNECT TO X2."
Run Code Online (Sandbox Code Playgroud)

当然,理想情况下,我想匹配技术词汇P1X2这里,但因为它们被"隐藏"在全大写句子中,并且因为这些技术词语没有特定的模式,所以这是不可能的.我再一次能忍受它,因为我的文件中的全大写句子并不常见.

谢谢!

Jay*_*Jay 56

在某种程度上,这将取决于你正在使用的RegEx的"味道".以下内容基于.NET RegEx,它\b用于字边界.在最后一个例子,它也使用负环视(?<!)(?!)以及非捕获括号(?:)

但是,基本上,如果术语始终包含至少一个大写字母后跟至少一个数字,则可以使用

\b[A-Z]+[0-9]+\b
Run Code Online (Sandbox Code Playgroud)

对于全大写和数字(总数必须为2或更多):

\b[A-Z0-9]{2,}\b
Run Code Online (Sandbox Code Playgroud)

对于全大写和数字,但从至少一个字母开头:

\b[A-Z][A-Z0-9]+\b
Run Code Online (Sandbox Code Playgroud)

granddaddy,用于返回具有大写字母和数字组合的项目,但在行的开头不是单个字母,而不是全部大写的行的一部分:

(?:(?<!^)[A-Z]\b|(?<!^[A-Z0-9 ]*)\b[A-Z0-9]+\b(?![A-Z0-9 ]$))
Run Code Online (Sandbox Code Playgroud)

分解:

正则表达式开头(?:.这?:表示 - 尽管后面的内容在括号中,但我对捕获结果不感兴趣.这被称为"非捕获括号".在这里,我正在使用paretheses,因为我正在使用交替(见下文).

在非捕获的parens中,我有两个由管道符号分隔的单独子句|.这是交替 - 就像"或".正则表达式可以匹配第一个表达式第二个表达式.这里的两个案例是"这是该行的第一个字"或"其他所有",因为我们有特殊要求在行的开头排除一个字母的单词.

现在,让我们看看交替中的每个表达式.

第一个表达是:(?<!^)[A-Z]\b.这里的主要条款是[A-Z]\b,任何一个大写字母后跟一个单词边界,可以是标点符号,空格,换行符等.之前的部分(?<!^)是"负面的背后".这是一个零宽度断言,这意味着它不会"消耗"字符作为匹配的一部分 - 这对于理解这一点并不重要..NET中负面lookbehind的语法是(?<!x),其中x是在main子句之前必须存在的表达式.这里的表达式只是简单的^,或者是行首,因此交替的这一面翻译为"任何单词,由不在行尾的单个大写字母组成".

好的,所以我们匹配不在行首的单字母大写单词.我们仍然需要匹配由所有数字和大写字母组成的单词.

这由交替中的第二个表达式的相对较小部分处理:\b[A-Z0-9]+\b.该\bs为单词边界,并[A-Z0-9]+匹配一个或多个数字和大写字母在一起.

表达的其余部分包含其他外观.(?<!^[A-Z0-9 ]*)是另一个负面的背后,表达是^[A-Z0-9 ]*.这意味着先前不能是所有大写字母和数字.

第二个看法是(?![A-Z0-9 ]$),这是一个负面的前瞻.这意味着以下内容不得全是大写字母和数字.

所以,总而言之,我们正在捕获所有大写字母和数字的单词,并从行的开头排除一个字母的大写字符,以及全部大写的行.

这里至少存在一个缺点,即第二个交替表达式中的外观独立地起作用,因此像"A P1应该连接到J9"这样的句子将匹配J9,但不匹配P1,因为P1之前的所有内容都是大写的.

有可能解决这个问题,但它几乎是正则表达式的三倍.尝试在一个正则表达式中做这么多,很少,如果有的话,只是做了.在您选择的编程语言中,您最好将工作分解为多个正则表达式或正则表达式和标准字符串处理命令的组合.


Rad*_*scu 6

不要做 [AZ] 或 [0-9] 之类的事情。改为使用 \p{Lu} 和 \d 。当然,这对于基于 Perl 的正则表达式风格是有效的。这包括java。

我建议你不要制作一些巨大的正则表达式。首先将文本分成句子。然后将其标记化(分成单词)。使用正则表达式检查每个标记/单词。跳过句子中的第一个标记。事先检查所有标记是否都是大写,如果是,则跳过整个句子,或者在这种情况下更改正则表达式。


Ano*_*on. 5

为什么你需要在一个怪物正则表达式中做到这一点?您可以使用实际代码来实现其中的一些规则,如果这些要求稍后发生变化,那么修改这些规则会容易得多。

例如:

if(/^[A-Z0-9\s]*$/)
    # sentence is all uppercase, so just fail out
    return 0;

# Carry on with matching uppercase terms
Run Code Online (Sandbox Code Playgroud)


Upg*_*ave 5

也许您可以先运行这个正则表达式,看看该行是否全部大写:

^[A-Z \d\W]+$
Run Code Online (Sandbox Code Playgroud)

只有当它是一条线时才会匹配 THING P1 MUST CONNECT TO X2.

否则,您应该能够通过以下方式提取单个大写短语:

[A-Z][A-Z\d]+
Run Code Online (Sandbox Code Playgroud)

那应该匹配“P1”和“J236” The thing P1 must connect to the J236 thing in the Foo position.