【问题标题】:PCRE Regex SyntaxPCRE 正则表达式语法
【发布时间】:2012-06-04 20:17:28
【问题描述】:

我想这或多或少是一个由两部分组成的问题,但首先是基础知识:我正在编写一些 PHP 以使用 preg_match_all 来查找以 {} 结尾的字符串的变量。然后它遍历每个返回的字符串,用 MySQL 查询中的数据替换它找到的字符串。

第一个问题是:有什么好的网站可以真正了解 PCRE 表达式的来龙去脉吗?我在 Google 上进行了很多搜索,但到目前为止我能找到的最好的是http://www.regular-expressions.info/。在我看来,那里的信息没有很好的组织,因为我不想在需要编写复杂的正则表达式时寻求帮助,所以请指点我几个网站(或几本书!)这将有助于我以后不必打扰你们。

第二个问题是:我有这个正则表达式

"/{.*(_){1}(.*(_){1}[a-z]{1}|.*)}/"

我需要它来捕获 {first_name}, {last_name}, {email} 等实例。这个正则表达式存在三个问题。

第一个是它将“{first_name} {last_name}”视为一个字符串,而它应该将其视为两个。我已经能够通过检查空间的存在来解决这个问题,然后在空间上爆炸。乱七八糟,但它有效。

第二个问题是它包含标点符号作为捕获字符串的一部分。因此,如果您有“{first_name} {last_name}”,那么它将逗号作为字符串的一部分返回。我已经能够通过简单地使用 preg_replace 删除句点、逗号和分号来部分解决这个问题。虽然它适用于这些标点符号,但我的逻辑无法处理感叹号、问号和其他所有内容。

我对这个正则表达式的第三个问题是它根本看不到 {email} 的实例。

现在,如果您可以、愿意并且有时间简单地将这个问题的解决方案交给我,谢谢您,因为这将解决我眼前的问题。但是,即使您可以做到这一点,请提供一个 lmgfty,它提供好的网站作为参考和/或一两本书,可以提供关于这个主题的良好教育。由于资金紧张,网站会更好,但如果一本书是解决方案,我会找到钱(假设我当地的图书馆系统无法获得上述数量)。

【问题讨论】:

  • 我真的很喜欢Mastering Regular Expressions 这本书。那本书中的内容比您可能永远使用的要多;非常彻底。
  • @JonahBishop:这是一本好书,但不太容易消化;)
  • @ClementSmith:您说它应该将其视为两个,但您的正则表达式是贪婪的。在合适的地方添加几个? :)
  • @JonahBishop:谢谢你的建议。我从图书馆订购了那本书。下周应该会到。

标签: regex pcre


【解决方案1】:

当时我发现PHP自带的PCRE语法参考相当不错:http://uk.php.net/manual/en/reference.pcre.pattern.syntax.php

让我们谈谈你的表达。它比必要的要冗长得多。在我们进行此操作时,我将对其进行简化。

查看您要匹配的内容的一种相当简单的方法:“找到{,然后是任意数量的字母或下划线,然后是}”。一个正则表达式是(在 PHP 的 string-y 语法中):'/\{[a-z_]+\}/'

这将匹配您的所有示例,但也匹配一些更狂野的示例,例如 {__a_b}。如果这不是一个选项,我们可以使用更复杂的描述:“找到{,然后是一堆字母,然后(尽可能经常)一个下划线,然后是一堆字母,然后是} ”。在正则表达式中:/\{([a-z]+(_[a-z]+)*\}/

第二个可能需要更多解释。由于我们要重复匹配_foo 段的内容,我们需要将其放在括号中。然后我们说:尽量多找这个,但如果根本找不到也没关系(这就是*的意思)。

既然我们有一些东西可以与您的尝试进行比较,那么让我们来看看是什么导致了您的问题:

  • 您的表达式匹配{} 中的任何字符,包括}{ 以及一大堆其他内容。换句话说,{abcde{_fgh} 将被您的正则表达式接受,{abcde} fg_h {ijkl} 也是如此。
  • 在第一个.* 之后,您有一个强制性的_(_){1}(与_ 的意思完全相同)说:不管发生什么,如果这不在这里就爆炸!显然你实际上并不想要这样,因为它永远不会匹配 {email}

以下是您的正则表达式匹配内容的完整描述:

  1. 匹配{
  2. 匹配_
  3. 完全匹配任何东西,只要你能匹配所有剩余的规则就可以了。
  4. 匹配_
  5. 匹配单个字母。
  6. 除了 _ 和单个字母之外,绝对任何事情都可以。
  7. 匹配}

这可能与您想要的相差甚远。不过不用担心。正则表达式需要一段时间才能习惯。我认为如果您从指令的角度考虑它会非常有帮助,即在构建正则表达式时,尝试将其构建为“找到这个,然后找到那个”等。然后找出正确的语法来实现正是这样。

这很难,主要是因为并非所有您可能在脑海中想出的指令都可以轻松转换为正则表达式...但这就是经验的来源。我向您保证,您很快就会把它记下来完全没有时间......如果你一开始就相当有条理地制作你的正则表达式。

祝你好运! :)

【讨论】:

  • 谢谢你。我以前没想过以这种方式考虑正则表达式。我想这只是因为缺乏经验,真的。感谢您的回复,并已将此页面添加为书签以供将来参考。 (我还从图书馆订购了@JonahBishop 推荐的书)
【解决方案2】:

对于 PCRE,我只是简单地消化了 PCRE 联机帮助页,但无论如何我的大脑都是这样工作的......

至于匹配分隔的东西,你通常有两种方法:

  1. 匹配第一个分隔符,匹配任何非结束分隔符,匹配结束分隔符。
  2. 匹配第一个分隔符,不贪婪地匹配任何东西,匹配结束分隔符。

例如对于您的情况:

  1. \{([^}]+)\}
  2. \{(.+?)\} - 注意 + 后面的 ?

我围绕您可能也想提取的内容添加了一个组。

还要注意,特别是在 #1 的情况下,但对于 #2,如果“点匹配任何东西”有效(dotall、单行或任何你最喜欢的正则表达式风格),它们也会匹配 -如果这是一个问题,您需要手动排除它以及您不想要的任何其他内容;如果您想要更像白名单的方法,请参阅上面的答案。

【讨论】:

    【解决方案3】:
    1. 这是good regex site
    2. 这是一个可以工作的 PCRE 正则表达式:\{\w+\}

    它的工作原理如下: 它基本上是在寻找{,然后是one ore more word characters,然后是}。有趣的是,单词字符类实际上也包含下划线。 \w本质上是[A-Za-z0-9_]的简写

    所以它基本上会匹配大括号内这些字符的任意组合,因为加号只会匹配非空的大括号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2014-08-02
      • 1970-01-01
      • 2013-12-31
      • 2014-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多