【问题标题】:Regex to separate list of parameters at commas, but ignore commas enclosed in quotation marks正则表达式以逗号分隔参数列表,但忽略引号中的逗号
【发布时间】:2021-02-03 15:55:35
【问题描述】:

我需要解析一个以逗号分隔的形式参数列表的字符串

key1=value1,key2=value2,key3=value3...

复杂之处在于可以将值括在引号中以允许它们包含空格和逗号等。当然,引号括起来的逗号不应算作分隔参数。 (引号之外的各个地方也可以有空格,可能应该忽略。)

我的想法是在逗号处拆分列表,然后在每个参数定义中,将键与等号处的值分开。所以对于split的参数,我需要找到有效的(不在引号内);我认为正则表达式是简洁和直接的方式。

以下是一些示例字符串:

  • Include="All Violations", CheckType=MaxTrans
  • MetricName = PlacedInstances, PlacedOnly = 1
  • CheckType=Hold, Include="reg2reg,in2reg,in2out,reg2out"
  • CheckType=Setup, Include="reg2reg,in2reg,in2out,reg2out(原文如此)

是的,最后一个格式不正确:值中缺少终止引号。

我发现this answer 很有帮助(正则表达式:/,(?=(?:(?:[^"]*"){2})*[^"]*$)/),除了解析格式不正确的那个。在我的情况下,我在等号中得到了额外的信息,这将允许解析那个。

我试过这个:(/(?<==[^"]+),/,它适用于格式不佳的那个,但我的第一个例子失败了。我认为我需要的是一种方法来查找逗号前面有一个等号,但在它们和前面的第一个等号之间有零个或两个引号(不仅仅是一个单引号)。但是如何在 Javascript Regex 中编写呢?

【问题讨论】:

    标签: javascript regex string-parsing parameter-list


    【解决方案1】:

    人们可以使用一种基于例如的方法。两个正则表达式 ...

    1. /,\s*(?=[^=,]+=)/
    2. /^(?<key>[^=\s]+)\s*="*(?<value>[^"]+)/

    第一个必须根据OP的要求split提供的字符串;因此它基于positive lookahead

    第二个将在一个操作中使用map 得到参数模板项的结果数组。每个项目将由尝试capture named groups 的正则表达式处理。此外,groupvalue 字段的字符串值将是trimmed。

    // see ... [https://regex101.com/r/nUc8en/1/]
    const regXParameterSplit = (/,\s*(?=[^=,]+=)/);
    
    // see ... [https://regex101.com/r/7xSwyX/1/]
    const regXCaptureKeyValue = (/^(?<key>[^=\s]+)\s*="*(?<value>[^"]+)/);
    
    const testSample = 'Include="All Violations", CheckType=MaxTrans, MetricName = PlacedInstances, PlacedOnly = 1, CheckType=Hold, Include="reg2reg,in2reg,in2out,reg2out", CheckType=Setup, Include="reg2reg,in2reg,in2out,reg2out,CheckType=Setup';
    
    function getKeyAndValue(template) {
      const { groups } = (regXCaptureKeyValue.exec(template) || {});
      if (groups) {
        groups.value = groups.value.trim();
      }
      return groups;
    }
    
    console.log(
      '... just splitting ...',
      testSample
        .split(regXParameterSplit)
    );
    console.log(
      '... the full approach ...',
      testSample
        .split(regXParameterSplit)
        .map(getKeyAndValue)
    );
    .as-console-wrapper { min-height: 100%!important; top: 0; }

    【讨论】:

    【解决方案2】:

    这样的事情会起作用:

    /(?:^|, *)(?<key>[a-z]+) *= *(?<value>[^\r\n,"]+|"[^\r\n"]+"?)/gmi
    

    https://regex101.com/r/z05WcM/1

    • (?:^|, *)(?&lt;key&gt;[a-z]+) 命名一个捕获组“key”,它被定义为一系列 alpha 字符,它们要么位于行首,要么位于逗号和可选空格之后
    • *= * - 赋值运算符(等号)两边可以有空格
    • (?&lt;value&gt;[^\r\n,"]+|"[^\r\n"]+"?) - 将捕获组命名为“值”,它可以是非逗号和非引号包含的字符串,或者如果它以引号开头,那么它可以有逗号和可选的结束引号

    但是如果你有像Include="All Viola\"tions" 这样的数据,那么它就会失败。

    请注意,我避免使用lookbehinds,因为并非所有浏览器都普遍支持它们。

    【讨论】:

      【解决方案3】:

      使用

      string.match(/\w+\s*=\s*(?:"[^"\n]*(?:"|$)|\S+(?=,|$))/g)
      

      proof

      说明

      --------------------------------------------------------------------------------
        \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                                 more times (matching the most amount
                                 possible))
      --------------------------------------------------------------------------------
        \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                                 more times (matching the most amount
                                 possible))
      --------------------------------------------------------------------------------
        =                        '='
      --------------------------------------------------------------------------------
        \s*                      whitespace (\n, \r, \t, \f, and " ") (0 or
                                 more times (matching the most amount
                                 possible))
      --------------------------------------------------------------------------------
        (?:                      group, but do not capture:
      --------------------------------------------------------------------------------
          "                        '"'
      --------------------------------------------------------------------------------
          [^"\n]*                  any character except: '"', '\n'
                                   (newline) (0 or more times (matching the
                                   most amount possible))
      --------------------------------------------------------------------------------
          (?:                      group, but do not capture:
      --------------------------------------------------------------------------------
            "                        '"'
      --------------------------------------------------------------------------------
           |                        OR
      --------------------------------------------------------------------------------
            $                        before an optional \n, and the end of
                                     the string
      --------------------------------------------------------------------------------
          )                        end of grouping
      --------------------------------------------------------------------------------
         |                        OR
      --------------------------------------------------------------------------------
          \S+                      non-whitespace (all but \n, \r, \t, \f,
                                   and " ") (1 or more times (matching the
                                   most amount possible))
      --------------------------------------------------------------------------------
          (?=                      look ahead to see if there is:
      --------------------------------------------------------------------------------
            ,                        ','
      --------------------------------------------------------------------------------
           |                        OR
      --------------------------------------------------------------------------------
            $                        before an optional \n, and the end of
                                     the string
      --------------------------------------------------------------------------------
          )                        end of look-ahead
      --------------------------------------------------------------------------------
        )                        end of grouping
      

      【讨论】:

      • 不错。但是,当没有右引号时,它似乎捕获了应该作为分隔符的逗号。这意味着我必须包含一个单独的步骤来删除这些逗号。
      • @JohnK 我想我设法解决了这个“错误”,请检查。
      猜你喜欢
      • 1970-01-01
      • 2011-07-13
      • 2013-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多