简单正则表达式存在问题

4
我有像这样的字符串:{$foo.bar}{$foo.bar.anything}

其中: foo 和 bar 和 anything 都是字母数字。

我想在PHP中使用preg_match(正则表达式)匹配上述2个字符串,但不包括没有点的字符串(例如:{$foo})。

非常感谢您的帮助。
7个回答

3
/{\$[\da-z]+(?:\.[\da-z]+)+}/i

匹配

{$foo.bar}
{$foo.Bar.anything}
{$foo.bar.anything1.anything2.anything3}
{$foo.bar.anything.a.b.c}

不匹配

{$foo}
{$foo.}
{$foo bar}
{$foo.bar anything}
{$foo.bar......anything..}
{$foo.bar.anything.}
{$foo.bar.anything.a.b.c..}

采用了Joe的PCRE不区分大小写的修饰符,以使其更简洁。

特别感谢sln一直以来的督促,直到完美为止。 :)


1
至少匹配 {$foo.}{$foo} - Shef
1
@Tim Cooper:回滚了,因为你搞砸了,双反斜杠“\”会匹配一个反斜杠“\”。 - Shef
@sln:感谢你指出这个问题。我想我已经修复了它。 - Herbert
@Herbert:越来越接近了,它仍然匹配{$foo.bar.anything.} - user557597
@sln:哇,你真是有毅力啊。 :D。通过这次最新的改进,正则表达式实际上变得更短了几个字符。不错! :) - Herbert

2
你可能需要使用 preg_match_all 而不是 preg_match - 正如其名称所示,它可以获取所有匹配项,而不仅仅是第一个。
至于你想要的正则表达式,类似下面这样的应该可以工作:
/\{\$[a-z0-9]+\.([a-z0-9\.]+)+\}/i

2
/(\{\$[a-z]+\.([a-z][a-z.])*[a-z]+\})/

首先匹配 foo 和一个点 {$foo.,然后是可选的任何字符和点 {$foo.bar.,最后是另一个字符串 {$foo.bar.anything}

圆括号中未转义的句点将匹配任何字符。 - Joe
@Joe:不,没关系,在字符类内部它会匹配点号。 - Shef
2
嗯,我不知道那个。但我确信未转义的 $ 在开头是试图匹配字符串的结尾:P - Joe
@Joe:一定要转义那个美元符号! :) - Shef
@Wulf:为什么要经历所有的重复(和回溯)?你不能把它简化成/(\{\$[a-z]+(?:\.[a-z]+)+\})/吗? - user557597

2

这是我的解决方案,具体提供了一些替代方案,取决于您需要提取的内容。

  1. 仅提取整个 {$aaa.bbb[.ccc[.ddd ...]]},前提是它至少包含一个点
  2. {$aaa.bbb} 中提取内容(例如 aaa.bbb
  3. 只考虑由两个或三个组成部分组成的标签(忽略 {$aaa}{$aaa.bbb.ccc.ddd})。

代码:

<?php

$subject = '{$foo.bar} {$foo.bar.baz} {$foo} {$another-foo.bar} {$foo.bar.baz.boh}';

print "Matching the whole string\n";
preg_match_all(
   '/{\$[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)+}/',
   $subject, $m);
print var_export($m) ."\n\n";

print "Matching only the content\n";
preg_match_all(
   '/{\$([a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)+)}/',
   $subject, $m);
print var_export($m) ."\n\n";

print "Matching for strings containing only 1 or two dots\n";
preg_match_all(
   '/{\$([a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+){1,2})}/',
   $subject, $m);
print var_export($m) ."\n\n";

2
假设PHP正则表达式与Perl相同。
^\w+\.[\.\w]+$

这意味着以一个或多个字母数字字符开头,后跟一个 . ,然后是一些字母数字字符或 . $ 代表直到字符串的结尾。

如果它不能以 . 结尾,则

^\w+\.[\.\w]+\w$

如果不允许使用..,那么情况会变得更加复杂,因为不是所有的正则表达式引擎都能够处理指定多个字符子表达式的重复。但如果您的引擎支持,我认为可以这样写:
^\w+(\.\w+)+$

这意味着从一个或多个字母数字开始,后跟一个或多个重复的 .,然后是一个或多个字母数字。 $ 表示直到字符串的末尾。

\w 匹配字母、数字和下划线。 - Shef
PHP正则表达式和Perl一样(当您使用preg_match时)。“p”代表PCRE(Perl兼容的正则表达式)。 - Herbert
@Sodved:我认为你想要[^\W_]+(?:\.[^\W_]+)+来减少下划线的影响。此外,不清楚是否需要^$锚定。 - user557597

2
\{\$[A-Za-z0-9]+\.[A-Za-z0-9]+\.?[A-Za-z0-9]*\}

2
值得注意的是,这只匹配string.substring.subsubstring,并且如果有任何字符串在 (1.2.3.4) 中具有超过 2 个句点,则不会匹配。 - Joe
@Joe:是的,没错。看起来这就是OP想要的,但也许我错了。 - Shef

2
\{\$[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+\}

首先匹配{$。然后匹配任何字母数字字符串。接着匹配以.开头的任何字母数字字符串。最后匹配}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接