Как заменить шаблон регулярного выражения шаблоном регулярного выражения?

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

Это моя текущая попытка:

$string = '26 14:46:54",,"2011-08-26 14:47:02",8,0,"BUSY","DOCUMENTATION","1314370014.18","","","61399130249","7466455647","from-internal","""Oh Snap"" <61399130249>","SIP/1037-00000014","SIP/CL-00000015","Dial","SIP/CL/61436523277,45","2011-08-26 14:47:06","2011-08-26 14:47:15","2011-08-26 ';
$pattern = '["SIP/CL/\d*?,\d*?",]';
$replacement = '"SIP/CL/\1|\2",';
$string = preg_replace($pattern, $replacement, $string);
print($string);

Но это просто заменяет \1 и \2 пробелами. Так что, очевидно, я не понимаю всей концепции.

Что я хочу в конце, так это изменить:

this: "SIP/CL/61436523277,45"
to: "SIP/CL/61436523277|45"

Эта запятая в плохо отформатированном CSV-файле сбивает с толку некоторые другие мои скрипты.


person Mattisdada    schedule 18.01.2012    source источник
comment
Это не кажется плохо отформатированным, так как оно заключено в кавычки... Вы ДЕЙСТВИТЕЛЬНО используете fgetcsv для этого , Вы не? Или str_getcsv, если это строка.   -  person Wrikken    schedule 18.01.2012
comment
Я не был, но я сейчас. Мне все равно нужно было изучить эту форму замены регулярных выражений. Так убил двух зайцев одним выстрелом :). Я знал о fgetcsv, но он не подходил для моих целей (это 1,8 ГБ + csv...., не могу загрузить все это в память), но str_getcsv работал хорошо! :)   -  person Mattisdada    schedule 18.01.2012
comment
ОК, для справки в будущем: fgetcsv также не считывает весь файл в память, а только построчно;)   -  person Wrikken    schedule 18.01.2012


Ответы (4)


Вам не хватает фигурных скобок, шаблон должен выглядеть так:

$pattern = '["SIP/CL/(\d*),(\d*)",]';
person Vyktor    schedule 18.01.2012
comment
Это было? Я чувствую себя таким foo'. Большое спасибо :) Это сработало отлично. - person Mattisdada; 18.01.2012
comment
вы изменили значение оператора non-gready, вне скобки. Должно быть (\d+?) - person meouw; 18.01.2012
comment
@user1130968 user1130968 отметить самый полезный ответ как ответ - лучший способ сказать спасибо здесь.) (так говорится в FAQ) - person Vyktor; 18.01.2012
comment
@meouw ты прав, я не заметил, что просто добавил фигурные скобки, я бы вообще не стал их использовать - person Vyktor; 18.01.2012
comment
Финал выглядел так: $pattern = '[SIP/CL/(\d*),(\d*),]'; $replacement = 'SIP/CL/\1|\2,'; - person Mattisdada; 18.01.2012

Обратные ссылки \1 и \2 в вашем $replacement предназначены для ссылки на захваченные группы в $pattern. Захваченные группы сохраняются, заключая их в скобки ().

Попробуйте (я изменил ваши разделители регулярных выражений [] на ! в ожидании ответа из комментариев ниже):

$pattern = '!"SIP/CL/(\d*?),(\d*?)",!';
$replacement = '"SIP/CL/\1|\2",';

Также обратите внимание, что, поскольку у вас есть конечная запятая в вашем $pattern, если ваш $string заканчивается на "SIP/CL/61436523277,45", это не будет преобразовано. Я бы рекомендовал удалить эту запятую.

Также ваше текущее регулярное выражение преобразует "SIP/CL/," в "SIP/CL/|". Если это не является вашим намерением, измените * после \d (т.е. 0 или более совпадений) на + (одно или несколько совпадений).

person mathematical.coffee    schedule 18.01.2012
comment
[ и ] в этом случае будут считаться разделителями, а не классом символов - person meouw; 18.01.2012
comment
шаблон 1 не будет SIP/CL/{numbershere} Итак, если вы хотите '"SIP/CL/(\d*?),(\d*?)",', иначе ваша первая ссылка будет забавной. Так как вашей заменой будет SIP/CL/SIP/CL/numbershere|numbersagain - person ThePrimeagen; 18.01.2012
comment
@meouw, я забыл об этом, ура. но тогда разве не должно быть [ и [ или ] и ], но не [ и ]? - person mathematical.coffee; 18.01.2012
comment
PHP, как и Perl, распознает правильно спаренные скобки как разделители, поэтому все [], (), {} и <> работают. Я думаю, что использовать их в PHP - плохая идея; достаточно сбивает с толку то, что, в отличие от Perl, вы должны использовать разделители регулярных выражений в дополнение к кавычкам. По крайней мере, любой, кто посмотрит на ваш код, задастся вопросом, понимаете ли вы, почему он действителен. ;) - person Alan Moore; 18.01.2012

Я думаю, вам нужно это:

$pattern = '["SIP/CL/(\d+),(\d+)",]';

Круглые скобки — () — фиксируют совпадение внутри, позволяя вам ссылаться на него в шаблоне замены.

Вы также можете упростить шаблон замены, расширив захваты в шаблоне соответствия:

$pattern = '[("SIP/CL/\d+),(\d+",)]';   
$replacement = '\1|\2';
person Andrew Cooper    schedule 18.01.2012

я сделал это

$string = '26 14:46:54",,"2011-08-26 14:47:02",8,0,"BUSY","DOCUMENTATION","1314370014.18","","","61399130249","7466455647","from-internal","""Oh Snap"" <61399130249>","SIP/1037-00000014","SIP/CL-00000015","Dial","SIP/CL/61436523277,45","2011-08-26 14:47:06","2011-08-26 14:47:15","2011-08-26 ';
$pattern = '/SIP\/CL\/([0-9]+),([0-9]+)/';
$replacement = 'SIP/CL/\1|\2';
$string = preg_replace($pattern, $replacement, $string);
print($string);
person ThePrimeagen    schedule 18.01.2012