【问题标题】:PHP preg_match with regex: only single hyphens and spaces between words continuePHP preg_match 与正则表达式:单词之间只有单个连字符和空格继续
【发布时间】:2011-02-08 23:29:59
【问题描述】:

我正在尝试编写一个正则表达式,它只允许在单词中使用单个连字符和单个空格,而不是在单词的开头或结尾。

我以为我是从昨天收到的answer 中整理出来的,但我才意识到有一个小错误,我不太明白,

为什么它不接受这样的输入,

'forum-category-b forum-category-a'
'forum-category-b Counter-terrorism'
'forum-category-a Preventing'
'forum-category-a Preventing Violent'
'forum-category-a International-Research-and-Publications'
'International-Research-and-Publications forum-category-b forum-category-a'

但这需要,

'forum-category-b'
'Counter-terrorism forum-category-a'
'Preventing forum-category-a'
'Preventing Violent forum-category-a'
'International-Research-and-Publications forum-category-b'

这是为什么呢?我该如何解决?下面是带有初始测试的正则表达式,但理想情况下它应该接受上面的所有组合输入,

$aWords = array(
    'a',
    '---stack---over---flow---',
    '   stack    over    flow',
    'stack-over-flow',
    'stack over flow',
    'stacoverflow'
);

foreach($aWords as $sWord) {
    if (preg_match('/^(\w+([\s-]\w+)?)+$/', $sWord)) {
        echo 'pass: ' . $sWord . "\n";
    } else {
        echo 'fail: ' . $sWord . "\n";
    }
}

接受/拒绝如下输入,

---stack---over---flow---
stack-over-flow- stack-over-flow2
   stack    over    flow

谢谢。

【问题讨论】:

  • 您可能想了解破折号标点符号的\p{Pd} 属性。

标签: php regex preg-match


【解决方案1】:

你的模式没有做你想做的事。让我们把它分开:

^(\w+([\s-]\w+)?)+$

它匹配仅由一个或多个模式序列组成的字符串:

\w+([\s-]\w+)?

...这是一个单词字符序列,后跟一个可选的其他单词字符序列,由一个空格或破折号分隔。

换句话说,您的模式搜索如下字符串:

xxx-xxxyyy-yyyzzz zzz

...但是您打算编写一个可以找到的模式:

xxx-xxxxxx-xxxxxx yyy

在您的示例中,这是匹配的:

Counter-terrorism forum-category-a

...但它被解释为以下序列:

(Counter(-terroris)) (m( foru)) (m(-categor) (y(-a))

如您所见,该模式并没有真正找到您要查找的单词。

这个例子不匹配:

forum-category-a Preventing Violent

...因为模式在遇到单个单词字符后跟空格或破折号时无法形成“单词字符、空格或破折号、单词字符”组:

(forum(-categor)) (y(-a)) <Mismatch: Found " " but expected "\w">

如果您将另一个字符添加到“forum-category-a”,例如“forum-category-ax”,它将再次匹配,因为它可能在“ax”处分裂:

(forum(-categor)) (y(-a)) (x( Preventin)) (g( Violent))

你真正感兴趣的是这样的模式

^(\w+(-\w+)*)(\s\w+(-\w+)*)*$

...它将找到可能包含破折号的单词序列,用空格分隔:

(forum(-category)(-a)) ( Preventing) ( Violent)

顺便说一句,我使用 Python 脚本对此进行了测试,并尝试将您的模式与正则表达式引擎的示例字符串“International-Research-and-Publications forum-category-b forum-category-a”进行匹配似乎陷入了无限循环……

import re
expr = re.compile(r'^(\w+([\s-]\w+)?)+$')
expr.match('International-Research-and-Publications forum-category-b forum-category-a')

【讨论】:

  • 非常感谢!你救了我的命!!我添加了另一行只接受字母数字字符的正则表达式 - /^[a-zA-Z0-9\-\s]+$/ 哈哈谢谢!
  • 感谢您的编辑。哇蟒蛇!!!它适用于 PHP。怎么来的!???哪种语言有错误!?签名....我猜这个正则表达式不正确 - /^(\w+([\s-]\w+)?)+$/ !
  • 我猜这与 Python 与 PHP 无关,但它是正在使用的正则表达式引擎的实现细节。可能 PHP 的 PCRE 引擎比 Python 的 SRE 引擎有更严格的圆检测。问题实际上是您的正则表达式模式,另请参阅regular-expressions.info/catastrophic.html
【解决方案2】:

您的模式([\s-]\w+)? 的一部分是问题所在。它只允许重复一次(尾随?)。尝试将最后一个 ? 更改为 * 看看是否有帮助。

不,我仍然认为这是问题所在。原始模式正在寻找重复 1 次以上的“word”或“word[space_hyphen]word”。这很奇怪,因为该模式应该属于另一个匹配项。但是切换问号worked for me

【讨论】:

    【解决方案3】:

    这个问题应该只有一个答案:

    /^((?&lt;=\w)[ -]\w|[^ -])+$/

    \w[ -]\w 所述只有 1 条规则,仅此而已。它以每个字符为粒度,不能是别的。其余部分添加 [^ -]。

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2020-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多