【问题标题】:Regex: Sub expressions?正则表达式:子表达式?
【发布时间】:2017-02-07 16:02:49
【问题描述】:

我需要创建一个匹配这个表达式的正则表达式:

replace:sub\:str:new\:Substr

不过,我必须小心不要匹配其他看起来相似的字符串。例如,这是一个不同的匹配:

slice:fromIndex[:toIndex]

具体来说:

  1. 字符串必须以replace: 开头。如果不匹配,则不匹配。
  2. 它必须匹配转义冒号:\:,但不能匹配非转义冒号::
  3. 必须有两个匹配项(子字符串和新子字符串)。例如,在示例字符串中,正则表达式将匹配:sub\:str 和 new\:Substr。
  4. 关键是要提取子字符串并替换它以供以后使用。该字符串将始终采用replace:<subString>:<replacementString> 格式。但是,subString 和 replacementString 都可以有转义冒号 :,这就是示例包含它们的原因。

我一直无法提出解决方案。虽然我不是 Regex 方面的专家,但我通常很能干。但到目前为止,我只能忽略replace: 并简单地匹配(?<=\:)(?:\\:|[^:])+ 以包含两个子字符串,但我最终也匹配了其他模式。如果我将后面的外观更改为 (?<=replace:) 我只匹配第一个子字符串。我只是不知道如何在不包含: 分隔符的情况下让它也匹配第二个子字符串。我怀疑我需要以某种方式嵌套表达式,但我完全没有成功。

注意:我可以用语言解决这个问题。我可以简单地检查字符串是否具有前缀 replace: 作为单独的检查。但如果可能的话,我真的很想完全在 Regex 中完成比赛。

更新(一些例子)

  • replace:sub\:str:new\:Substr 匹配:sub\:str、new\:Substr
  • replace:subString:replacment 匹配:subString、replacement
  • replace:UserId:user\:ID 匹配:UserId、user:ID
  • replace:UserName:Aaron Hayman 匹配:UserName、Aaron Hayman
  • replace:userId:uid90809y087 匹配:userId、uid90809y087

  • rep:userId:user 匹配:无

  • replace:UserName 匹配:无
  • slice:908:1098 匹配:无

这应该给你一个例子。作为背景,在这个字符串被解析之后,它将被应用为另一个模板字符串的一种过滤器。

【问题讨论】:

  • 整个 sub\:str 是一个中间有东西的子字符串,还是 sub\: (和 new\: )部分也是静态的?我的意思是,replace:sub\\:(.+):new\\:(.+) 会起作用吗?
  • 第 3 点不太清楚。你能展示你想要什么吗?是sub\:str 和new\:Substr 还是别的什么?
  • 输入和输出示例?
  • @Toto 我已经澄清了问题并添加了输出应该是什么。

标签: regex nsregularexpression


【解决方案1】:

匹配你在 C 字符串文字中可能拥有的所有转义序列的正则表达式看起来像

replace:([^:\\]*(?:\\.[^:\\]*)*):([^:\\]*(?:\\.[^:\\]*)*)

见regex demo

注意:如果它必须出现在字符串的开头,请在模式状态处添加^。

详情:

  • replace: - 文字字符序列
  • ([^:\\]*(?:\\.[^:\\]*)*) - 捕获组 1 匹配
    • [^:\\]* - 除了 : 和 \ 之外的 0+ 个字符
    • (?:\\.[^:\\]*)* - 零个或多个序列:
      • \\. - 任何转义字符(\ 和任何字符)
      • [^:\\]* - 除了 : 和 \ 之外还有 0+ 个字符
  • : - 未转义的:
  • ([^:\\]*(?:\\.[^:\\]*)*) - 见上文。

【讨论】:

    【解决方案2】:

    怎么样:

    ^replace:(\w+\\:\w+):(\w+\\:\w+)
    

    第一组将包含sub\:str,第二组将包含new\:Substr

    根据 OP 的编辑的新版本:

    ^replace:([^:]+(?:\\:)?[^:]+):([^:]+(?:\\:)?[^:]+)
    

    它适用于所有给定的测试用例

    如果您不想在整个比赛中使用replace,请将其放在lookbehind 中:

    (?<=^replace:)([^:]+(?:\\:)?[^:]+):([^:]+(?:\\:)?[^:]+)
    

    【讨论】:

    • 我认为 OP 如果在允许超过 1 的事情后转义 :
    • 这行得通。这不完全是我所要求的,只是因为我不想将 replace: 作为匹配的一部分,但是它允许我单独使用正则表达式并访问捕获组而不是所有匹配(包括 @987654329 @)。
    • @AaronHayman:你可以看看后面:(?&lt;=^replace:)
    【解决方案3】:

    相当复杂,但您可以嵌套环顾四周:

    replace:(.+?(?!(?&lt;=\\):)):(.+(?!(?&lt;=\\):))

    Demo

    这将确保在replace: 之后任何字符后面都没有: 本身前面没有\

    缺点:
    如果是 3 部分(第三部分未转义 :),第二部分将包含所有内容,请参阅演示了解我的意思。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多