提取符合特定条件的“单词”

时间:2011-06-25 14:59:08

标签: php regex preg-match-all

我有以下字符串:

  

SEDCVBNT S800BG09 7GFHFGD6H 324235346 RHGF7U S8-00BG / 09 7687678

以及以下正则表达式:

preg_match_all('/\b(?=.+[0-9])(?=.+[A-Z])[A-Z0-9-\/]{4,20}/i', $string, $matches)

我想要实现的目标是返回所有“单词”:

  • 包含至少1个数字
  • 至少包含1个字母
  • 可能包含'/'
  • 可能包含' - '

不幸的是,上面的正则表达式返回:

Array ( [0] => Array ( [0] => SEDCVBNT [1] => S800BG09 [2] => 7GFHFGD6H [3] => 324235346 [4] => RHGF7U [5] => S8-00BG/09 ) ) 

我不希望退回'SEDCVBNT'或'324235346'。

我搜索高低,尝试了上述正则表达式的许多小改动,但我只是完全坚持这一点。我真的很感激任何帮助。

提前致谢。

2 个答案:

答案 0 :(得分:2)

您需要稍微高级的正则表达式语法。

我提出的正则表达式是

(?<=\s|^)(?=[\w/-]*\d[\w/-]*)(?=[\w/-]*[A-Za-z][\w/-]*)([\w/-])+(?=\s|$)

我们来解释一下:

  • 语法[\w/-]出现了很多;这意味着“任何单词字符(包括字母,数字,重音字母等)或斜线或短划线” - 实际上,您认为所有字符都是有效令牌的一部分。
  • 正则表达式使用正向前瞻以确保在尝试匹配的位置,以下文本确实满足特定条件。积极的前瞻看起来像这样:(?=[\w/-]*\d[\w/-]*)
  • 它还使用正面(最后一个:(?=\s|$)负面(开头:(?<=\s|^))前瞻以确保仅匹配如果整个文本标记在空白字符后面开始或在输入字符串的开头(\s|^后跟一个空白字符或终止输入字符串({{1 }})。
  • 由于两个内部先行模式几乎与捕获组模式\s|$相同,实际上我使用它们只匹配匹配多个模式的文本:两个前瞻最后的捕获组模式。
  • 第一个前瞻确保下一个令牌包含至少一个数字(([\w/-])+)。
  • 第二个前瞻确保下一个令牌包含至少一个字母(\d)。
  • 捕获组与一个或多个字词和/或A-Za-z/匹配。

因此,要匹配的捕获组,正在检查的文本必须:

  1. 以空格或输入字符串的开头开头(这可以防止在不允许的字符后开始的部分字匹配)
  2. 在下一段允许的字符中包含至少一位数字(第一个正向前瞻)
  3. 在下一段允许的字符中包含至少一个字母(第二个正向前瞻)
  4. 仅包含字词-/(捕获组)。
  5. 通过空格或输入字符串的结尾跟随(这可以防止以不允许的字符结尾的部分字匹配)。
  6. 这正是您所需要的。 :)

    <强> See it in action!

    注意: refiddle.com似乎不适合使用负面反馈,因此链接后的正则表达式不包含初始-部分。这意味着它会错误地匹配(?<=\s|^)中的DEF456

答案 1 :(得分:0)

这是原始正则表达式:\b(?=\S*?\d)(?=\S*?[a-z])\S+?(?=$|\s)

preg_match_all('/\b(?=\S*?\d)(?=\S*?[a-z])\S+?(?=$|\s)/i', $string, $matches)