Regex для разделения списка параметров запятыми, но игнорирует запятые, заключенные в кавычки

Мне нужно проанализировать строку, состоящую из списков параметров формы, разделенных запятыми

      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(так в оригинале)

Да, последнее неправильно сформировано: в значении отсутствует закрывающая кавычка.

Я нашел этот ответ полезным (regex: /,(?=(?:(?:[^"]*"){2})*[^"]*$)/), за исключением разбора плохо сформированного. В моем случае у меня есть дополнительная информация в знаке равенства, которая позволила бы разобрать ее.

Я пробовал это: (/(?<==[^"]+),/, который работает для плохо сформированного, но не подходит для моего первого примера. Я думаю, что мне нужен способ найти запятые, которым предшествует знак равенства, но которые имеют либо ноль, либо две кавычки (а не только одну кавычку) между ними и первым предшествующим знаком равенства. Но как мне написать это в Javascript Regex?

3 ответа

Можно использовать подход, основанный, например, на двух регулярных выражениях...

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

Первый долженsplitпредоставленная строка в соответствии с требованиями OP; таким образом, он основан на положительном взгляде вперед.

Второй будет использоваться в операции, которая делаетmapрезультирующий массив элементов шаблона параметров . Каждый элемент будет обрабатываться регулярным выражением, которое пытается захватить именованные группы . Кроме того, строковое значение a groupх valueполе будетtrimмед.

Использовать

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

Смотрите доказательство .

Объяснение

      --------------------------------------------------------------------------------
  \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

Что-то вроде этого будет работать:

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

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

  • (?:^|, *)(?<key>[a-z]+)назовите «ключ» группы захвата, который определяется как последовательность альфа-символов, которые находятся либо в начале строки, либо после запятой и необязательного пробела.
  • *= *- оператор присваивания (знак равенства) может иметь пробелы с обеих сторон
  • (?<value>[^\r\n,"]+|"[^\r\n"]+"?)- назовите группу захвата как «значение», которое представляет собой либо строку без запятой и кавычек, содержащую строку, либо, если она начинается с кавычки, она может иметь запятые с необязательной закрывающей кавычкой.

Но если у вас есть такие данные, как Include="All Viola\"tions"тогда это не удастся.

Обратите внимание, что я избегал использования lookbehind, потому что они не повсеместно поддерживаются во всех браузерах.

Другие вопросы по тегам