Как функция разделения javascript работает через разделители, если указано несколько разделителей - PullRequest
0 голосов
/ 12 января 2019

Я разделяю строку, используя функцию разделения Javascript с несколькими разделителями. Хотя я заставляю его работать, его поведение меня озадачивает. Ищите объяснение этому поведению

У меня есть эта строка ниже -

let z = 'c4 <= v4';

Я разделил это с console.log(z.split(/(<|=|<=)/)). Строка может содержать <, = или <=, поэтому я делю ее на 3 разделителя. Это дает мне [ 'c4 ', '<', '', '=', ' v4' ], чего я не ожидаю. Я ожидал [ 'c4 ', '<=', ' v4' ].

Затем я полагаю, что split разбирается по списку разделителей, поэтому сначала он делится на <, а затем разделяет результат на =, что объясняет пустой элемент между <и =. Затем, когда он дошел до разделителя <code><=, он не смог найти ничего в результате.

Итак, чтобы доказать свою мысль, я попытался console.log(z.split(/(=|<=)/)). Следуя моей логике, я ожидал, что результат будет [ 'c4 <', '=', ' v4' ], так как я ожидал, что split использует сначала = в качестве разделителя. Тем не менее, фактический результат составляет [ 'c4 ', '<=', ' v4' ]. Как будто разделение только что пропущено через разделитель =.

Я могу заставить его работать правильно, если я упорядочу порядок разделителей console.log(z.split(/(<=|<|=)/)) и получу [ 'c4 ', '<=', ' v4' ], что усиливает мое мышление, поскольку <= является первым указанным разделителем.

Я искал целую группу и не мог найти объяснения этому поведению. Как работает разделение через разделители?

Большое спасибо заранее

Ответы [ 2 ]

0 голосов
/ 12 января 2019

В большинстве движков регулярных выражений, когда у вас есть несколько альтернатив, которые могут совпадать с одной и той же строкой, он использует первую совпадающую. Таким образом, имеет значение, пишете ли вы <|<= или <=|<.

Если строка ввода foo<=bar, первая версия будет соответствовать просто <, потому что это первая альтернатива, а вторая - <=.

Это объясняется более подробно на Regular-Expression.info .

Таким образом, решение в общем случае состоит в том, чтобы записать ваше регулярное выражение с альтернативами в порядке убывания длины, например, z.split(/(<=|<|=)/)

Существуют некоторые движки регулярных выражений, которые всегда пытаются найти самое длинное совпадение, а не первое совпадение (приведенная выше страница называет их «текстовыми»). Но JavaScript этого не делает.

0 голосов
/ 12 января 2019

Порядок заместителей имеет значение здесь. Если вы разделите на /(<|=|<=)/, то он будет разделен при первом совпадении, которое он найдет, это <. Это означает, что оставшаяся строка больше не имеет этого <=, она просто имеет =, поэтому она снова разделяется на это. Если вы измените порядок, вы можете убедиться, что <= совпадает до < и =:

let z = 'c4 <= v4';
console.log(z.split(/(<=|=|<)/))

Случай /(=|<=)/ более интересен, потому что он соответствует <=.

let z = 'c4 <= v4';
console.log(z.split(/(=|<=)/))

Причина этого в том, что механизм регулярных выражений совпадает с нетерпением. При сканировании строки первое потенциальное совпадение, которое она видит, - <. В этот момент он знает, что у него есть потенциальное совпадение с альтернативой <=, поэтому если продолжить, перейдите к следующему символу, чтобы увидеть, действительно ли оно совпадает. Оказывается, так и происходит, и считается, что матч сделан. Ему никогда не нужно проверять = в одиночку.

Вы можете избежать всего этого, если будете использовать что-то вроде: /([<=]+)/ Но это будет более щадящим и соответствует любой комбинации < и =

let z = 'c4 <= v4 == x4 =< z6 = a9 < b9';
console.log(z.split(/([<=]+)/g))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...