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

时间:2011-01-04 20:54:40

标签: regex match uppercase

我有以下技术字符串:

"The thing P1 must connect to the J236 thing in the Foo position."

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

示例,在:

"A thing P1 must connect ..." 

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

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

示例:

"THING P1 MUST CONNECT TO X2."

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

谢谢!

6 个答案:

答案 0 :(得分:50)

在某种程度上,这会因您使用的RegEx的“味道”而异。以下内容基于.NET RegEx,它使用\b作为字边界。在最后一个示例中,它还使用否定外观(?<!)(?!)以及非捕获括号(?:)

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

\b[A-Z]+[0-9]+\b

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

\b[A-Z0-9]{2,}\b

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

\b[A-Z][A-Z0-9]+\b

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

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

<强>击穿:

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

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

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

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

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

由交替中的第二个表达式的相对较小部分处理:\b[A-Z0-9]+\b\b代表字边界,[A-Z0-9]+代表一个或多个数字和大写字母。

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

第二个环视是(?![A-Z0-9 ]$),这是一个负面的预测。这意味着以下必须都是大写字母和数字。

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

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

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

答案 1 :(得分:3)

为什么你需要在一个怪物正则表达式中执行此操作?您可以使用实际代码来实现其中一些规则,如果这些要求稍后更改,这样做会更容易修改。

例如:

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

# Carry on with matching uppercase terms

答案 2 :(得分:3)

也许你可以先运行这个正则表达式来查看该行是否全部为大写:

^[A-Z \d\W]+$

只有当它像THING P1 MUST CONNECT TO X2.

这样的行时才会匹配

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

[A-Z][A-Z\d]+

这应匹配The thing P1 must connect to the J236 thing in the Foo position.

中的“P1”和“J236”

答案 3 :(得分:3)

不要做[A-Z]或[0-9]之类的事情。请改为\ p {Lu}和\ d。当然,这对基于perl的正则表达式有效。这包括java。

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

答案 4 :(得分:2)

我绝不是一个正则表达的大师。但试试:

<[A-Z0-9][A-Z0-9]+>

<           start of word
[A-Z0-9]    one character
[A-Z0-9]+   and one or more of them
>           end of word

我不会尝试整个大写句子的奖励积分。和合

答案 5 :(得分:1)

对于您建议的第一个案例,您可以使用:'[[:blank:]] + [A-Z0-9] + [[:blank:]] +',例如:

echo“事物P1必须连接到Foo位置的J236事物”| grep -oE'[[:blank:]] + [A-Z0-9] + [[:blank:]] +'

在第二种情况下,你可能需要使用别的东西,而不是正则表达式,也许是一个带有技术词典的脚本......

干杯,费尔南多