【问题标题】:regex to parse string with escaped characters正则表达式用转义字符解析字符串
【发布时间】:2013-11-20 10:21:38
【问题描述】:

我正在从格式化的字符串中读取信息。 格式如下:

"foo:bar:beer:123::lol"

“:”之间的所有内容都是我想用正则表达式提取的数据。如果一个 : 后跟另一个 : (如“::”),则此数据必须是“”(一个空字符串)。

目前我正在用这个正则表达式解析它:

(.*?)(:|$)

现在我想到“:”也可能存在于数据中。所以它必须逃脱。 示例:

"foo:bar:beer:\::1337"

如何更改我的正则表达式,使其也匹配“\:”作为数据?

编辑:我使用 JavaScript 作为编程语言。它似乎对复杂的正则表达式有一些限制。该解决方案也应该适用于 JavaScript。

谢谢, 麦克法兰

【问题讨论】:

    标签: javascript regex


    【解决方案1】:
    var myregexp = /((?:\\.|[^\\:])*)(?::|$)/g;
    var match = myregexp.exec(subject);
    while (match != null) {
        for (var i = 0; i < match.length; i++) {
            // Add match[1] to the list of matches
        }
        match = myregexp.exec(subject);
    }
    

    输入:"foo:bar:beer:\\:::1337"

    输出:["foo", "bar", "beer", "\\:", "", "1337", ""]

    你总是会得到一个空字符串作为最后一个匹配。鉴于您还希望空字符串在分隔符之间匹配(以及 JavaScript 中缺少后向断言),这是不可避免的。

    说明:

    (          # Match and capture:
     (?:       # Either match...
      \\.      # an escaped character
     |         # or
      [^\\:]   # any character except backslash or colon
     )*        # zero or more times
    )          # End of capturing group
    (?::|$)    # Match (but don't capture) a colon or end-of-string
    

    【讨论】:

    • 我收到这个输出:["foo", "", "bar", "", "beer", "", "\:", "", "", "1337" , ""]
    • 啊,对。 RegexBuddy “足够聪明”,可以忽略无关的空匹配,JavaScript 和 Python(我现在正在测试它)不是。看看能不能找到解决办法。
    • 您更新的示例与预期的数据匹配,但它一直返回 ["", ""]。在您的示例中,循环将导致无限循环,因为 match 永远不会为空。我已将 while 循环限制为进行 [subject.match(myregexp).length-1] 迭代。不过,我会将您的答案标记为正确,因为正则表达式很棒。非常感谢您的努力。
    • 嗯,我可能错了,但是您似乎不支持\出现在令牌中。例如,以: 分隔的值可以是转义码:\n:\b:\c,甚至可以是字符a:b:,:;:\\:\:,即ab,;\、@ 的列表987654334@。即使 OP 没有明确指定,如果不支持斜线转义,您的解决方案也不会感觉完整。到目前为止,您似乎并不支持它。
    【解决方案2】:

    这里有一个解决方案:

    function tokenize(str) {
      var reg = /((\\.|[^\\:])*)/g;
      var array = [];
      while(reg.lastIndex < str.length) {
        match = reg.exec(str);
        array.push(match[0].replace(/\\(\\|:)/g, "$1"));
        reg.lastIndex++;
      }
      return array;
    }
    

    它根据: 字符将字符串拆分为标记。

    • 但是,如果您希望 : 字符成为令牌的一部分,则可以使用 \ 对其进行转义。
    • 如果您希望 \ 成为令牌的一部分,可以使用 \ 转义它
    • 任何其他\ 都不会被解释。 (即:\a 仍然是 \a
    • 因此,只要事先正确格式化数据,您就可以将任何数据放入令牌中。

    这是一个带有字符串\a:b:\n::\\:\::x 的示例,它应该给出这些令牌:\ab\n&lt;empty string&gt;\:x

    >>> tokenize("\\a:b:\\n::\\\\:\\::x");
    ["\a", "b", "\n", "", "\", ":", "x"]
    

    为了更清楚:放入标记器的字符串将被解释,它有 2 个特殊字符:\:

    • \ 只有在后面跟着 \: 时才会有特殊含义,并且会有效地“转义”这些字符:意味着它们将失去其对分词器的特殊含义,它们将被视为任何正常字符(因此将成为令牌的一部分)。
    • : 是分隔 2 个标记的标记。

    我意识到 OP 并没有要求斜杠转义,但其他查看器可能需要一个完整的解析库,允许数据中的任何字符。

    【讨论】:

      【解决方案3】:

      使用否定的lookbehind断言。

      (.*?)((?<!\\):|$)
      

      这只会匹配:,如果它不是前面是\

      【讨论】:

      • 它在我的正则表达式测试器中有效,但在我的代码中无效。我使用 JavaScript 作为编程语言。尽管我找不到任何定义它们的页面,但它似乎有一些限制。
      • JavaScript 不支持后向断言。
      • 好吧,就地使用一个字符类,比如([^\\]:|$)
      • 嗯,我猜也可能会出现斜杠\\。所以你的正则表达式会错误地避免\\: 字符串,但其中有一个有效的令牌。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      相关资源
      最近更新 更多