Как исключить строку из preg_split, если строка уже содержит разделяемый символ в PHP? - PullRequest
2 голосов
/ 06 августа 2011

Я использую функцию preg_split в PHP, чтобы создать один массив, содержащий несколько разных элементов. Тем не менее, я хочу исключить строку, которая содержит один из элементов, которыми я preg_splitting.

$array['stuff'] = preg_split('/\[#]|\ &amp  |\ &amp |\&amp |\&amp|\ &amp|\ &gt  |\ &gt |\&gt |\&gt|\ &gt|\ &  |\ & |\& |\&|\ &|\ \/  |\ \/ |\\/ |\\/|\ \/|\ >  |\ > |\> |\>|\ >|\ ,  |\ , |\, |\,|\, |\ ::  |\ :: |\:: |\ ::|\::|\ ::|\ :  |\ : |\: |\:|\ :|\ -  |\ - |\- |\-|\ -/', $array['stuff'] ) ;

То, что я хотел бы сделать, это исключить строку, такую ​​как 'foo-bar', из соответствия для разделения, потому что она содержит тире. 'foo-bar' должен точно соответствовать моим целям.

Ответы [ 2 ]

3 голосов
/ 06 августа 2011

Результирующее регулярное выражение будет очень сложным, особенно если у вас есть много исключений, таких как 'foo-bar'.

Вы должны использовать условный подшаблон с условием lookbehind в качестве условия и lookahead в качестве его шаблона yes.:

$res = preg_split('/(?(?<=foo)\-(?!bar)|\-)/', 'aasdf-fafsdf-foo-bar-asdf' );
var_dump( $res );

результат:

array(4) {
  [0]=>
  string(5) "aasdf"
  [1]=>
  string(6) "fafsdf"
  [2]=>
  string(7) "foo-bar"
  [3]=>
  string(4) "asdf"
}

Позвольте мне объяснить, что здесь происходит.\- означает

Соответствует любому символу тире.

, но нам нужно:

Соответствует любому символу тире, который не является частьюfoo-bar.

Так как мы не можем реализовать это в регулярном выражении как есть, мы его немного изменим:

Соответствует любому символу тире, который if , перед которым стоит foo, не следует за баром.

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

(?(condition)yes-pattern|no-pattern)

Наше «условие» будет «предшествовать foo», чтобы проверить, что мы используем lookbehind:

(?<=foo)

Если это правда, мы должны искать «черту, за которой не следует строка», чтобы сделатьчто мы используем негативный взгляд:

\-(?!bar)

И это становится нашим "образцом да".Наш «не шаблон» должен быть \- или «любой тире».Полное регулярное выражение будет:

(?(?<=foo)\-(?!bar)|\-)

ОБНОВЛЕНИЕ: чтобы включить это в ваше текущее регулярное выражение, измените эту часть в конце:

|\ -  |\ - |\- |\-|\ -/

на

|\s?(?(?<=foo)\-(?!bar)|\-)\s?/
0 голосов
/ 02 августа 2018

Хотя я не даю никаких гарантий, что мое решение более эффективно, чем ничейный шаблон двойного обхода для в этом случае, я думаю, что мое решение немного легче читать. (*SKIP)(*FAIL) эффективно сопоставляет и отбрасывает подстроки, которые вы хотите игнорировать. В некоторых случаях этот подход может быть очень полезным / эффективным / поддерживаемым.

Код: ( Демо )

$string = 'I-like-candy-and-foo-bar-sandwiches';
var_export(preg_split('~foo-bar(*SKIP)(*FAIL)|-~', $string));

Выход:

array (
  0 => 'I',
  1 => 'like',
  2 => 'candy',
  3 => 'and',
  4 => 'foo-bar',
  5 => 'sandwiches',
)

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

Код: ( Демо )

$string = 'I-like-candy-and-foo-bar-sandwiches';
var_export(preg_split('~(?<!foo)-(?!bar)~', $string));

Выход:

array (
  0 => 'I',
  1 => 'like',
  2 => 'candy',
  3 => 'and',
  4 => 'foo-bar',
  5 => 'sandwiches',
)

p.s. Если у вас может есть дефис в начале или конце входной строки, и вы не хотите, чтобы пустые элементы генерировались с помощью preg_split(), тогда используйте 0 и PREG_SPLIT_NO_EMPTY в качестве параметров 3 и 4 (соответственно) в вызове функции.

...