2013-02-20 3 views
2
$s = "bla..bla"; 
$s =~ s/([^%])\./$1/g; 

Я думаю, он должен заменить все вхождения ., что не является после % с символом, который находится перед ..Как заменить все вхождения определенных символов их предшественниками?

Но $s: bla.bla, но должно быть blabla. В чем проблема? Я знаю, что могу использовать кванторы, но мне нужно сделать это так.

+0

Какой результат вы ожидаете? –

+0

Я ожидаю, что blabla – Krab

+0

На самом деле, нет, вам это не нужно (нужно делать это таким образом). Поскольку буквальная точка не является процентом, мы все готовы знать, что любой поток точек, которым предшествует символ, который не является процентом, мы можем уничтожить. Если так получилось, что у нас есть «% ...', тогда двигатель re с радостью сохранит точку, следующую за процентом, считая ее несимметричным символом, предшествующим строке точек, и удалит остальные. – Axeman

ответ

8

Когда глобальное регулярное выражение ищет строку, оно не будет найдено совпадающих совпадений.

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

Вместо этого используйте отрицательные 'назад, чтобы выполнить утверждение о том, что предыдущий символ не %:

$s =~ s/(?<!%)\.//g; 

Обратите внимание, что если вы используете положительные назад', как (?<=[^%]), вы не замените ., если это первый символ в строке.

6

Проблема в том, что даже с флагом /g каждая подстановка начинается с того места, где было остановлено предыдущее. Вы пытаетесь заменить a. на a, а затем a. с a, но вторая замена не произойдет, потому что a уже «проглотил» предыдущую замену.

Одно исправление использовать zero-width lookbehind assertion:

$s =~ s/(?<=[^%])\.//g; 

, который приведет к удалению . что не первый символ в строке, и это не предшествует %.

Но вы могли бы на самом деле хотите:

$s =~ s/(?<!%)\.//g; 

, который приведет к удалению . что не предшествует %, даже если он является первого символа в строке.

3

Намного проще, чем смотреть-зады является использование:

$s =~ s/([^%])\.+/$1/g; 

Это заменяет любую последовательность из одного или нескольких точек после символа, кроме % ничем.

+0

Я не думаю, что регулярное выражение делает то, что вы думаете. Могу ли я рекомендовать обратную косую черту перед этой точкой? – tjd

+0

@tjd: yup - опечатка. Благодарю. –

+0

+1 для устранения проблемы перекрытия. Помните, '\ K', и вам не нужно« переносить ($) 1 ». 'S/[^%] \ K \. + // G'. (Начиная с 5.10!) – Axeman