Регулярные выражения: замена кавычек между парными скобками

ЕСТЬ РЕШЕНИЕ ЗАКРЫТО
#1 19 декабря 2015 в 05:17
Знатоки регулярных выражений, помогите пожалуйста. Нужно в строке заменить все двойные кавычки на одинарные, но только в том случае, если они находятся между первыми парными квадратными скобками в одной строке. Вне парных квадратных скобок, а также во второй и далее парах, кавычки заменять не нужно. Внутри между этими первыми скобками двойных кавычек может быть сколько угодно и находиться они могут в любых местах. Пар скобок в строке, а также строк в тексте тоже может быть любое количество. Менять предполагаю функцией mb_ereg_replace(), так как в строке будут символы в Юникоде.

Например, исходная строка
  1. что-то "в кавычках" ["data":"Config":private] ещё что-то "в кавычках" ["var"] ещё текст
Нужно получить
  1. что-то "в кавычках" ['data':'Config':private] ещё что-то "в кавычках" ["var"] ещё текст

И ещё вторая задача: нужно удвоить количество пробелов, находящихся в начале строки до первого символа/цифры/знака. Если поможет для решения, то пробелы всегда идут парами, то есть, их всегда чётное количество. Но двойные пробелы также могут встречаться в середине строки — их трогать не нужно. Количество строк в тексте может быть любое.
Конечно можно разбить текст на строки, потом в цикле подсчитать в каждой пробелы в начале и добавить ещё столько же, а потом собрать заново в единый текст. Но это решение выглядит как-то некрасиво. Может можно это сделать регуляркой?

То есть было
  1. Тут 2 пробела
  2. { а тут 4 пробела }
  3. Опять 2 пробела
Нужно получить
  1. Тут 4 пробела
  2. { а тут 8 пробелов }
  3. Опять 4 пробела
#2 19 декабря 2015 в 22:41
  1.  
  2. $ott = 'что-то "в кавычках" ["data":"Config":private] ещё что-то "в кавычках" ["var"] ещё текст';
  3.  
  4. if ( preg_match( '`^([^\[]+?\[)"([^\]]+)\]`', $ott, $_arr ) ) {
  5.  
  6. $_tt = str_replace( '"', "'", '"' . $_arr[2] );
  7. $_tt = str_replace( '"' . $_arr[2], $_tt, $ott );
  8.  
  9. echo $_tt;
  10. }
  11.  
  1.  
  2. $ott = <<<_OUT
  3. Тут 2 пробела
  4. { а тут 4 пробела }
  5. Опять 2 пробела
  6. _OUT;
  7.  
  8. // second template
  9.  
  10. $_tt = preg_replace_callback( '`^(\s+)(\S)`m',
  11. function ( $_arr ) {
  12. return $_arr[1] . $_arr[1] . $_arr[2];
  13. },
  14. $ott
  15. );
  16.  
  17. echo "<pre>$_tt</pre>";
  18.  
#3 19 декабря 2015 в 22:47

Менять предполагаю функцией mb_ereg_replace(), так как в строке будут символы в Юникоде.

WebMan

— в данном случае не критично, ибо меняете вы обычные ASСII символы ( однобайтные )…
#4 19 декабря 2015 в 22:52
то есть в первом случае кавычки ( 039 ) на ( 034 ),
во втором случае пробелы удваиваете ( 032 )…
#5 19 декабря 2015 в 23:06
Спасибо, • Mike •, сейчас проверю.
#6 19 декабря 2015 в 23:11
«Эхо слушать не нужно (echo)», это для отладки, просто забирайте $_tt «из эха» в нужную локацию…
#7 19 декабря 2015 в 23:49
Посмотрел решение для первой задачи. Для одной строки оно работает. Если в переменной несколько строк, то меняет кавычки только в первой.
Например, если такая:
  1. $ott = 'что-то "в кавычках" ["data"] ещё что-то "в кавычках" ["var"] ещё текст\n\r';
  2. $ott .= 'что-то "в кавычках" [123] ["new":"Module":private] ещё что-то "в кавычках" ["var"] ещё текст\n\r';
  3. $ott .= 'что-то "в кавычках" ["qwerty"] ещё что-то "в кавычках" ["var"] ещё текст\n\r';
то меняет только первое ['data'].

Я нашёл рабочий способ при использовании mb_ereg_replace_callback(). Но эта функция доступна только начиная с PHP 5.4, а по требоавниям к Двойке нужно чтобы работало и на 5.3. Можно было бы заменить её чем-то типа preg_replace_callback(), но я не уверен, что она не испортит строку в Юникоде. Кстати, сейчас и проверю. 😊
#8 20 декабря 2015 в 00:19
Ура! Первую задачу решил так:
  1. '/^\s*\[.+?\]/m',
  2. function ($matches) {
  3. return str_replace('"', "'", $matches[0]);
  4. },
  5. $out);
Оказалось, что в моей задаче во всех строках текста перед первой прямоугольной скобкой всегда будут только пробелы. Это упростило задачу. Проблем с Юникодом не обнаружил.
Спасибо за подсказку, • Mike •!
#9 20 декабря 2015 в 00:19

Нужно в строке заменить все двойные кавычки на одинарные, но только в том случае, если они находятся между первыми парными квадратными скобками в одной строке.

WebMan
— Ваша задача и была для одной строки сформулирована )

Если нужна многострочная обработка, нужно использовать модификатор в паттерне “m” как во второй задаче.
И внутри условия прогонять циклом…
Или так же с помощью preg_replace_callback();

Для юникода можно использовать модификатор “u” в хвосте паттерна, но повторюсь в вашем случае не критично так как вы анализируете и заменяете однобайтные символы из обычной раскладки ASCII
#10 20 декабря 2015 в 00:28
Вторую задачу решил способом, похожим на предложенный Майком. Только сделал удвоение пробелов прямо в операторе замены:
  1. $out = mb_ereg_replace('(^\s+)(.*)', '\\1\\1\\2', $out, '');
Ещё раз благодарю, • Mike •! Если Вы не предполагаете ничего больше сюда писать, то тему можно закрывать.
#11 20 декабря 2015 в 00:30
То есть, даже если строка содержит юникодные символы, но поиск и замена идёт по однобайтным символам, то можно использовать однобайтные функции без риска потерять юникод?
#12 20 декабря 2015 в 00:31
  1.  
  2. $matches[0] — это вся исходная строка…
  3.  
  4. '^\s*[.+?\]/m' — «дословно» расшифровывается так:
  5. ^ — за началом строки (в мульти режиме),
  6. следует или не следует ( по квантификатору * ) \s некий пробельный символ,
  7. после которого следует открывающая квадратная скобка,
  8. за ней любое количество любых символов, но
  9. до первой встреченной закрывающей квадратной скобки.
  10.  
  11.  
я бы не сказал что это «рабочий» вариант )
#13 20 декабря 2015 в 00:35
Если вы окончательно разобрались, то конечно можете закрыть тему…
#14 20 декабря 2015 в 00:39

То есть, даже если строка содержит юникодные символы, но поиск и замена идёт по однобайтным символам, то можно использовать однобайтные функции без риска потерять юникод?

WebMan

— чаще всего — да, но есть еще параметры внутренних функций самого PHP и тп, надо проверять в реальном серверном окружении…
«безопсными» я бы назвал только первые 127 символов для ASCII они одинаковы для любой кодировки…
#15 20 декабря 2015 в 00:44

Оказалось, что в моей задаче во всех строках текста перед первой прямоугольной скобкой всегда будут только пробелы.

WebMan
Поэтому достаточно найти подстроку между первой квадратной скобкой после пробелов с начала строки и следующей обратной. И в этой подстроке произвести замену. Что я и сделал. Или я что-то упустил?
Используя этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.