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 ответа
Можно использовать подход, основанный, например, на двух регулярных выражениях...
Первый должен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, потому что они не повсеместно поддерживаются во всех браузерах.