2

我想编写 php 正则表达式来从文本中查找大写字符串,它也可以包含一个数字和空格。

例如,从这个文本中"some text to contain EXAM PL E 7STRING uppercase word"我想得到 string- EXAM PL E 7STRING

找到的字符串应该只以大写开头和结尾,但在中间,没有大写字母也可以包含(但不一定)一个数字和空格。所以,正则表达式应该匹配任何这些模式

1) EXAMPLESTRING               - just uppercase string
2) EXAMP4LESTRING              - with number
3) EXAMPLES TRING              - with space
4) EXAM PL E STRING            - with more than one spaces
5) EXAMP LE4STRING             - with number and space
6) EXAMP LE 4ST RI NG          - with number and spaces 

并且总长度字符串应等于或大于 4 个字母

我写了这个正则表达式'/[A-Z]{1,}([A-Z\s]{2,}|\d?)[A-Z]{1,}/',它可以找到前 4 个模式,但我想不出它也匹配最后 2 个模式。

谢谢

4

2 回答 2

5

有一个巧妙的技巧叫做前瞻。它只是检查当前位置之后的内容。这可用于检查多个条件:

'/(?<![A-Z])(?=(?:[A-Z][\s\d]*){3}[A-Z])(?!(?:[A-Z\s]*\d){2})[A-Z][A-Z\s\d]*[A-Z]/'

第一个环视实际上是一个lookbehind 并检查没有以前的大写字母。对于无论如何都会失败的字符串,这只是一点加速。第二个环视(前瞻)检查是否至少有四个字母。第三个检查没有两位数。其余的只是匹配一个允许字符的字符串,以大写字母开头和结尾。

请注意,在两位数的情况下,这根本不匹配(而不是将所有内容匹配到第二个数字)。如果您确实想在这种情况下进行匹配,则可以将“1 digit”规则合并到实际匹配中:

'/(?<![A-Z])(?=(?:[A-Z][\s\d]*){3}[A-Z])[A-Z][A-Z\s]*\d?[A-Z\s]*[A-Z]/'

编辑:

正如 Ωmega 指出的那样,如果第二个数字之前的字母少于四个,但之后的字母更多,这将导致问题。这实际上非常困难,因为断言需要在第二个数字之前有超过 4 个字母。由于我们不知道这四个字母中第一个数字出现在哪里,我们必须检查所有可能的位置。为此,我将完全取消前瞻,并简单地提供三种不同的选择。(我将保留后视作为对不匹配部分的优化。)

'/(?<![A-Z])[A-Z]\s*(?:\d\s*[A-Z]\s*[A-Z]|[A-Z]\s*\d\s*[A-Z]|[A-Z]\s*[A-Z][A-Z\s]*\d?)[A-Z\s]*[A-Z]/'

或者在这里添加评论:

'/
(?<!         # negative lookbehind
    [A-Z]    # current position is not preceded by a letter
)            # end of lookbehind
[A-Z]        # match has to start with uppercase letter
\s*          # optional spaces after first letter
(?:          # subpattern for possible digit positions
    \d\s*[A-Z]\s*[A-Z]
             # digit comes after first letter, we need two more letters before last one
|            # OR
    [A-Z]\s*\d\s*[A-Z]
             # digit comes after second letter, we need one more letter before last one
|            # OR
    [A-Z]\s*[A-Z][A-Z\s]*\d?
             # digit comes after third letter, or later, or not at all
)            # end of subpattern for possible digit positions
[A-Z\s]*     # arbitrary amount of further letters and whitespace
[A-Z]        # match has to end with uppercase letter
/x'

这在 Ωmega 的冗长测试输入上给出了相同的结果。

于 2012-11-09T13:50:11.977 回答
2

我建议使用正则表达式模式

[A-Z][ ]*(\d)?(?(1)(?:[ ]*[A-Z]){3,}|[A-Z][ ]*(\d)?(?(2)(?:[ ]*[A-Z]){2,}|[A-Z][ ]*(\d)?(?(3)(?:[ ]*[A-Z]){2,}|[A-Z][ ]*(?:\d|(?:[ ]*[A-Z])+[ ]*\d?))))(?:[ ]*[A-Z])*

(见这个演示)。

[A-Z][ ]*(?:\d(?:[ ]*[A-Z]){2}|[A-Z][ ]*\d[ ]*[A-Z]|(?:[A-Z][ ]*){2,}\d?)[A-Z ]*[A-Z]

(见这个演示

于 2012-11-09T14:02:02.517 回答