2014-09-10 3 views
4

Вот код, который я пытаюсь запустить:фиксированной длины регулярное выражение просмотра назад жалуется переменной длины 'назад

$str = 'a,b,c,d'; 
return preg_split('/(?<![^\\\\][\\\\]),/', $str); 

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

/(?<![^\\][\\]),/ 

Это простой отрицательный lookbehind с фиксированной длиной для «впереди чего-то, что не является обратным слэшем, а затем что-то!».

Это регулярное выражение прекрасно работает на http://www.phpliveregex.com

Но когда я иду, и на самом деле попытка запустить приведенный выше код, я плюнул назад ошибку:

Warning: preg_split() [function.preg-split]: Compilation failed: lookbehind assertion is not fixed length at offset 13 

Чтобы сделать дела хуже, товарищ программист протестировал код на своем сервере 5.4.24 PHP, и он работал нормально.

Это заставляет меня думать, что мои проблемы связаны с конфигурацией моего сервера, с которой у меня очень мало контроля. Мне сказали, что моя версия PHP, если 5.2. *

Есть ли способы обхода (альтернативы) для preg_replace(), которые могут не иметь этой проблемы?

+0

При запуске кода действительно работает нормально и разбивает результаты. – hwnd

+6

Возможно, не настоящий 5.2. Он работает для меня, и вы можете видеть, в каких версиях он терпит неудачу [здесь] (http://3v4l.org/PlBUB) (сбой в 4.3.0 - 4.4.4, 5.0.0 - 5.1.6). Имейте в виду, что вы используете версию _ancient_ PHP. – Wrikken

+0

@Wrikken О, мой, никогда не знал о инструменте. Это замечательно.) – raina77ow

ответ

3

Проблема вызвана ошибкой зафиксированной в PCRE 6.7. Цитирование the changelog:

A negated single-character class was not being recognized as fixed-length in lookbehind assertions such as (?<=[^f]) , leading to an incorrect compile error "lookbehind assertion is not fixed length"

PCRE 6,7 был введен в PHP 5.2.0, в ноябре 2006 года, как вы до сих пор эта ошибка, это означает, что он все еще не существует на вашем сервере - так для обхода проблемы на основе PREG-сплит, вы должны использовать шаблон без отрицательного класса символов. Например:

$patt = '/(?<!(?<!\\\\)\\\\),/'; 
// or... 
$patt = '/(?<![\x00-\x5b\x5d-\xFF]\x5c),/'; 

Однако, я считаю, весь подход немного странно: что, если , символ предшествует ровно три обратных косых черт? Или пять? Или любое нечетное число из них? В этом случае запятая должна считаться «экранированной», но, очевидно, вы не можете создать выражение переменной длины, чтобы покрыть эти случаи.

На второй мысли, можно использовать вместо preg_match_all с общим чередованием трюком, чтобы покрыть уцелевшие символы:

$str = 'e ,a\\,b\\\\,c\\\\\\,d\\\\'; 
preg_match_all('/(?:[^\\\\,]|\\\\(?:.|$))+/', $str, $matches); 
var_dump($matches[0]); 

Demo.

Я действительно думаю, что я охватывал все вопросы здесь, эти замыкающие косые были убийцами)

+0

Большое спасибо! Хорошо составленный, полностью информативный ответ. Точно такой контент SO нужен :) –

1

способ избежать отрицания класса символов (я пишу \x5c вместо многих обратных косых черт, чтобы быть более ясными)

$result = preg_split('/(?<!(?!\x5c).\x5c),/s', $str); 

О самом подходе:

Если вы пытаетесь разделить на запятой, которые не экранированы, вы ошибаетесь с lookbehind, так как вы не можете проверить и неопределенное количество обратных косов в запятой. У вас есть несколько возможностей для решения этой проблемы:

$result = preg_split('/(?:[^\x5c]|\A)(?:\x5c.)*\K,/s', $str); 

или

$result = preg_split('/(?<!\x5c)(?:\x5c.)*\K,/s', $str); 

или PHP> 5.2.4

$result = preg_split('/\x5c{2}(*SKIP)(?!)|(?<!\x5c),/s', $str); 
0

Я думаю, что вы используете более старую версию PHP, так как я ваша ошибка поднимается на PHP 5.1.6 или ниже ,

Вы можете проверить non working demo here

enter image description here

С другой стороны, она работает для PHP 5.2.16 или выше:

Working demo

enter image description here

Смежные вопросы