Сопоставление определенного символа, если он находится между двумя цифрами с регулярным выражением

Для некоторой обработки данных мне нужно разбить строку на несколько элементов. Пример входной строки:

'one, two & three and four-five 123-456'

Теперь мне нужно разделить эту строку на элементы, где возможными разделителями являются ,, &, (space), and, -. Но, и это тот момент, когда я застрял, он не должен разбиваться на -, когда он находится между двумя числами.

Я использую PHP и preg_split для фактического разделения, но мне нужен шаблон регулярного выражения для соответствия разделителям, исключая разделитель -, когда он находится между двумя числами (цифры, но также может быть 123-456). Подавление пробелов вокруг каждого элемента выполняется с помощью trim() в PHP.

Я использую следующий шаблон регулярного выражения:

/(and|,|\s|&)|\D(-)\D/

Вывод (после использования preg_split и т. д.):

[0] => one
[1] => two
[2] => three
[3] => fou
[4] => ive
[5] => 123-456

Работает правильно, но также принимает последнюю и первую букву окружающего текста в качестве разделителя -. Элемент 123-456 правильный, так как он не должен совпадать (и разделяться с preg_split) на -, когда он непосредственно окружен числом.

Ожидаемый результат:

[0] => one
[1] => two
[2] => three
[3] => four
[4] => five
[5] => 123-456

Любая помощь приветствуется, если какой-либо информации не хватает, дайте мне знать, и я обновлю свой вопрос.


person B_s    schedule 31.08.2016    source источник


Ответы (1)


Вам нужно использовать предпросмотр и просмотр назад (более известный как обход):

/and|,|\s|&|(?<!\d)-(?!\d)/

Это будет делать именно то, что следует из названия — осмотритесь, чтобы проверить, соответствует ли указанный шаблон, не сопоставляя его. В этом случае он будет соответствовать только -, не окруженному с обеих сторон числовыми символами (\d), но совпадение будет только самим -.

В этом случае (?<!\d) является отрицательным просмотром назад — он будет смотреть назад, чтобы увидеть, не соответствует ли непосредственно предшествующая строка не шаблону. Если это так, он сообщает, что совпадение не удалось, и движется дальше. Точно так же (?!\d) является отрицательным опережением — он делает то же самое, но в противоположном направлении. Поскольку - зажато между ними, эффект «соответствует только -, если он не имеет числовых символов с обеих сторон».

person Sebastian Lenartowicz    schedule 31.08.2016
comment
Спасибо. Это решило мой вопрос. Я приму ваш ответ через несколько минут, когда это позволит мне. Ради интереса, с чем связана разница в обозначениях первой части? Он работает точно так же, как мой, но делает ли он что-то еще? - person B_s; 31.08.2016
comment
Я добавил краткое объяснение. - person Sebastian Lenartowicz; 31.08.2016
comment
Последняя сторона чередования должна быть (?<!\d)-(?!\d), в противном случае она не совпадает с начальной и конечной -. - person revo; 31.08.2016
comment
@revo: Хороший улов. Отредактировано. - person Sebastian Lenartowicz; 31.08.2016
comment
@SebastianLenartowicz Спасибо за дополнительное объяснение. Можете ли вы объяснить, почему вам не нужно соответствие () вокруг первой части and|,|\s|&? Кроме того, я пытаюсь понять это как можно лучше, @revo, что означает, что начальный и конечный - не будут совпадать? - person B_s; 31.08.2016
comment
Поскольку простая () (скобки) — это группа захвата — в вашем сценарии она не нужна, поэтому я ее удалил. Допустим, у вас есть разделитель, который может быть либо and, либо andson. Тогда, например, вы могли бы сделать что-то вроде /and(son)?|foo|bar/ — скобки используются для группировки son, поэтому он работает как группа с помощью квантификатора ? (необязательно). Это регулярное выражение будет эквивалентно /and|andson|foo|bar/. - person Sebastian Lenartowicz; 31.08.2016
comment
@SebastianLenartowicz Я понимаю, большое спасибо! - person B_s; 31.08.2016
comment
Рад помочь. :) - person Sebastian Lenartowicz; 31.08.2016