【问题标题】:How do I make this regex more general, sometimes it works and sometimes it doesn't如何使此正则表达式更通用,有时有效,有时无效
【发布时间】:2009-06-26 09:17:21
【问题描述】:

我在 Java 应用程序中使用了以下正则表达式。有时它可以正常工作,有时却不能。

<!-- <editable name=(\".*\")?> -->(.*)<!-- </editable> -->

有时我会在它之前/之后有空格,有时会有文本。标签内的区域也是如此。

主要问题是 name=(\".*\")?> 有时匹配的比它应该的要多。我不确定这是否是显而易见的问题,只需查看此代码即可。

【问题讨论】:

  • 对我来说,您似乎正在尝试使用正则表达式处理 XML。你为什么这样做?
  • 好吧,我之前尝试过 XML 解析,但它们似乎不起作用,因为页面的其余部分肯定不是有效的 XML。坦率地说,清理工具似乎也很难清理这些东西。因为我可以控制自己进入每个页面的这些标签,所以我认为 Regex 是最好的方法。

标签: java regex validation robustness


【解决方案1】:

XML 不是常规语言,HTML 或任何其他具有“嵌套”结构的语言也不是。不要尝试用正则表达式解析它。

Choose an XML parser.

【讨论】:

  • 即使您有一个输入数据保证没有嵌套的情况,*ML 仍然足够复杂,以至于在极窄的应用程序之外,手动正则表达式通常是不正确的。因此,即使您当前的数据对于正则表达式来说足够简单,也可以使用真正的 XML 解析器。
  • +1 -- @Svante:我确信仅靠“不要使用正则表达式执行 XML/HTML”帖子就可以达到每日“200 次代表”上限。 ;-)
  • @kd304,使用正确的解析器通常比摆弄错误的工具更快、更容易。正则表达式不是一个神奇的黑匣子,它是一个解析正则语言的工具。
  • @Tomalak,我也有这种感觉。
  • @Jason Day:还有一些人知道关于正则表达式的流行语录。 SCNR ;-)
【解决方案2】:

正如其他人指出的那样,与“name”属性匹配的贪婪.*(点星号)需要设为非贪婪(.*?)甚至更好,替换为否定字符类(@ 987654323@) 所以无论正则表达式的其余部分发生什么,它都不能匹配结束引号。一旦你解决了这个问题,你可能会发现你和另一个点星有同样的问题;你也需要让它不贪婪。

Pattern p = Pattern.compile(
    "<!--\\s*<editable\\s+name=\"([^\"]*)\">\\s*-->" +
    "(.*?)" +
    "<!--\\s*</editable>\\s*-->",
    Pattern.DOTALL);

我不明白你关于空格的评论的重要性。如果你说的是换行符和/或回车符,DOTALL 修饰符让点匹配那些——当然,\s 也匹配它们。

我以 Java 字符串文字的形式写了这个,以避免混淆你需要反斜杠的位置以及需要多少反斜杠。在“原始”正则表达式中,每个空格简写中只有一个反斜杠 (\s*),并且不需要转义引号 ("[^"]*")。

【讨论】:

  • 哦,没注意到我的回答是逃跑了。谢谢。
【解决方案3】:

例如,如果 name 是某种标识符,我会将 .* 替换为 [\w-]*。

或[^\"]*,因此它不会捕获结尾双引号。

编辑:

正如在其他帖子中提到的,您可能会考虑使用简单的 DOM 遍历、基于 XPath 或 XQuery 的评估过程,而不是简单的正则表达式。但请注意,您仍然需要在过滤过程中使用正则表达式,因为您只能通过针对正则表达式测试它们的主体来找到目标 cmets(因为我怀疑主体从样本中判断是不变的)。

编辑 2:

可能是注释正文的前导、尾随或内部空格使您的正则表达式失败。考虑将\s* 放在开头和结尾,加上\s+ 在类似属性的东西之前。

<!--\s*<editable\s+name=(\"[^\"]*\")?>\s*-->(.*)<!--\s*</editable>\s*-->

或者当您在基于 XML 的搜索上进行过滤时:

"\\s*<editable\\s+name=(\"[^\"]*\")?>\\s*"
"\\s*</editable>\\s*"

编辑 3: 修复了两次转义。谢谢艾伦 M。

【讨论】:

  • \w 匹配字母、数字和下划线,因此 [\w\d\-_] 只需为 [\w-] (如果是列出的第一个或最后一个字符)。
【解决方案4】:

* 乘数默认为“贪婪”,这意味着它尽可能匹配,同时仍然成功匹配模式。

您可以使用 *? 禁用此功能,请尝试:

(\".*?\")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 2013-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-12
    相关资源
    最近更新 更多