Регулярные выражения: как получить эффект оператора AND THEN в составном выражении? - PullRequest
1 голос
/ 13 апреля 2019

Я изо всех сил пытаюсь работать с регулярными выражениями. Я думаю, что понимаю индивидуальные выражения, но объединение чего-то вместе делает меня совершенно тупым. Я не понимаю использование чего-то, эквивалентного оператору AND, чтобы соединить нужные части вместе в «полное» выражение соответствия.

Например, я хотел бы разбить строку на массив, разбивая любые значения от <1> до <57> и </1> до </57>.

Итак, я подумал, что мне нужно что-то вроде:

( '<' or '<\/' ) and ( [1-9] or [1-4][0-9] or [5][0-7] ) and '>'

Я могу получить <<1-4] [0-9]> отдельно для работы или </ [1-4] [0-9]>, но в сочетании с '|' он возвращает частичные совпадения или не определено между полными совпадениями.

Не могли бы вы сказать мне, что я не понимаю? Прилагается мой пример.

Если нажать «Попробовать» для первого выражения, оно выдает пустые значения после каждого <21> или </21>. Это печатает как неопределенный в console.log, когда я проверяю это. Второе выражение выдает < и </ после каждого тега. Я не понимаю этого, не говоря уже о том, как преобразовать более полное выражение ранее в этом вопросе в regExp.

Желаемый вывод:

'This is a', '<21>', 'test', '<\/21>', '.'

Спасибо.

Сложение Получив ответ Георга на этот вопрос, я заинтересовался поиском метода экранирования этих тегов, тем более что в настоящее время не поддерживается отрицательный просмотр, за исключением только Chrome. Под этим я подразумеваю, что \<21> будет считаться обычным текстом и не будет разбивать строку в этой точке. Если вас интересует что-то подобное, вы, вероятно, найдете ответ на мой следующий вопрос, заданный Revo here , весьма полезным.

let b, B = document.querySelectorAll('button');

for ( b of B ) b.addEventListener( 'click', split_str, false );

function split_str( evt )
 {
   let e = evt.currentTarget,
       r = new RegExp( e.previousElementSibling.value ),
       s = e.parentNode.previousElementSibling.value;
   e.parentNode.lastElementChild.textContent = s.split(r);   
 }
div > div  { border: 1px solid rgb(150,150,150); width: 500px; height: 200px;padding: 5px; }

input { border: 1px solid rgb(150,150,150); width: 500px; margin-bottom: 20px; padding:5px; }
<input type='text' value="This is a<21>test</21>.">

<div>

<input type='text' value="(<[1-4][0-9]>)|(<\/[1-4][0-9]>)"> <button>try</button>

<input type='text' value="((<|<\/)[1-4][0-9]>)"> <button>try</button>

<div></div>

</div> 

Ответы [ 3 ]

2 голосов
/ 13 апреля 2019

Вы почти получили это.Это действительно так же просто, как заменить 'или' на | и заменить and на конкатенацию.Затем убедитесь, что ваши группы не совпадают, добавив ?: в начало каждого:

(?:<|<\/)(?:[1-9]|[1-4][0-9]|[5][0-7])>

В MDN есть объяснение взаимодействия split и регулярных выражений .Но краткое объяснение примера:

'hi_joe'.split('_'); // ['hi', 'joe']
'hi_joe'.split(/_/); // ['hi', 'joe']
'hi_joe'.split(/(_)/); // ['hi', '_', 'joe']
'hi_joe'.split(/(?:_)/); // ['hi', 'joe']

Обновление за комментарий , если вы хотите добавить <##> в свой массив результатов, оберните регулярное выражение в дополнительныйнабор паренов.

((?:<|<\/)(?:[1-9]|[1-4][0-9]|[5][0-7])>)

1 голос
/ 13 апреля 2019

Хорошо, давайте начнем с числа штука.Это нормально, за исключением того, что технически нет необходимости заключать в скобки один символ [5]

 [1-9] | [1-4][0-9] | 5[0-7]

(используйте пробелы здесь и ниже для ясности).

Для первой части, изменение вроде a | ab читается лучше, когда написано как ab?, то есть «a, а затем, необязательно, b`. Это дает нам

 < \/ ?

Теперь« и »(или, скорее,« и тогда ») оператор, который вы искали, очень прост в языке регулярных выражений - это ничего. То есть a and then b - это просто ab.

Однако, если объединить обе части просто, как это

a  x | y | z

это было бы ошибкой, потому что | имеет низкий приоритет, так что это будет интерпретироваться как

ax | y | z

, что не то, что мы хотим. Поэтому нам нужно поместить число вПарены, по причинам, которые будут объяснены ниже, эти парены также должны быть не захватывающими:

<\/?  (?: [1-9] | [1-4][0-9] | 5[0-7] )

Это соответствует нашим разделителям, но нам также нужно все промежуточное, поэтому мы собираемся split входные данные. split обычно возвращает массив строк, которые не соответствуютch разделитель:

"a,b,c".split(/,/) => a b c

Если мы тоже хотим включить разделитель, его нужно поместить в группу захвата:

"a,b,c".split(/(,)/) => a , b , c

, поэтому нам нужно один раз обернуть все в пареныеще раз:

(  <\/?  (?: [1-9] | [1-4][0-9] | 5[0-7] )  )

и в этом причина ?: - мы хотим, чтобы все это было записано, а не числовая часть.

Соединение всего этого, похоже, помогает:

s = "This is a<21>test</21>."


console.log(s.split(/(<\/?(?:[1-9]|[1-4][0-9]|5[0-7])>)/))

Надеюсь, это проливает свет

0 голосов
/ 13 апреля 2019

Как я понимаю, регулярное выражение состоит в том, что, если специально не указано иное, например, в предложении OR, все, что вы определяете как регулярное выражение, имеет форму AND.[a-z] будет соответствовать одному символу, тогда как [a-z][a-z] будет соответствовать одному символу И другому символу.

В зависимости от вашего случая использования приведенное ниже регулярное выражение может быть тем, что вам нужно.Как вы можете видеть, он захватывает все между <number></number>.

<[1-5][0-9]>([\s\S]*?)<\/[1-5][0-9]>

<[1-5][0-9]> matches <number> where number is between 00 and 59.
[\s\S]*? matches every single character there is, including new lines, between zero and unlimited times.
</[1-5][0-9]> matches </number> where number is between 00 and 59.

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

let str = '<10>Hello, world!</10>';

let reg = /<[1-5][0-9]>([\s\S]*?)<\/[1-5][0-9]>/g;

let matches = Array.from( str.matchAll(reg) );

console.log(matches[0][1]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...