我有以下字符串:
SEDCVBNT S800BG09 7GFHFGD6H 324235346 RHGF7U S8-00BG/09 7687678
下面的regex:
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
。
3条答案
按热度按时间0s0u357o1#
对于这个问题,您需要稍微高级的正则表达式语法。
我想出来的正则表达式是
让我们来解释一下:
[\w/-]
经常出现;这意味着“任何单词字符(包括字母、数字、重音字母等)或斜线或破折号”--实际上,您认为是有效标记的一部分的所有字符。(?=[\w/-]*\d[\w/-]*)
。(?=\s|$)
)* 和 * 负(在开始时:(?<=\s|^)
)lookahead,以确保仅当整个文本标记在空白字符之后开始或在输入字符串的开头(\s|^
)* 并且 * 后跟空白字符或终止输入字符串(\s|$
)时才进行匹配。([\w/-])+
相同,实际上我只使用它们来匹配匹配 * 多个 * 模式的文本:两个lookaheads * 和 * 捕获组模式在最后。\d
)。A-Za-z
)。/
和-
。因此,要使捕获组匹配,所检查的文本必须:
1.前面有空格或输入字符串的开头(这可以防止在不允许的字符之后开始部分字匹配)
1.在下一段允许的字符中至少包括一个数字(第一个正先行)
1.在下一段允许的字符中至少包含一个字母(第二个正先行)
1.仅包含单词字符
/
和-
(捕获组)。1.后面跟着空格或输入字符串的结尾(这可以防止部分单词匹配以不允许的字符结尾)。
这正是你所需要的。:)
**注意:**refiddle.com似乎不能很好地处理负向后查找,因此链接后的regexp不包括初始的
(?<=\s|^)
部分。这意味着它将错误地匹配ABC123$DEF456
中的DEF456
。3qpi33ja2#
不能依赖字边界标记(
\b
)来识别该任务的“字”的边缘,因为例如,以斜线结尾的字后面跟着空格将不满足字边界。字边界仅适用于确定\w
和\W
之间的零宽度位置(反之亦然)。代码:(Demo)
ergxz8rk3#
下面是原始正则表达式:
\b(?=\S*?\d)(?=\S*?[a-z])\S+?(?=$|\s)