PHP preg_replace вставляет строку там, где ее нет

У меня есть переменная $var, которая содержит строку.

Пример:

$var = "one, two , three = ?, four = 'val', five  , six = 1, seven, eight = 'val' , nine";

Я хочу отредактировать $var с помощью preg_replace() таким образом, чтобы $var выглядел так:

"one = ?, two = ?, three = ?, four = 'val', five = ?, six = 1, seven = ?, eight = 'val', nine = ?"

Я имею в виду: если столбцу не присвоено значение, установите для него ' = ?' и удалите ненужные пробелы.

Я попробовал следующее регулярное выражение, но это даже не близко:

$sql['set'] = preg_replace("/(\w+)\s?,/", "$1 = ?,", $sql['set']);

Я искал решения, но я не могу охватить все возможности.


person Alex Rosca    schedule 11.01.2019    source источник
comment
Почему это даже не близко? regex101.com/r/gDIrMS/1   -  person Dharman    schedule 11.01.2019
comment
Если вопрос касается регулярного выражения, вот пример того, как это сделать: regex101.com/r/pM4bV7/3   -  person Ravshan Abdulaev    schedule 11.01.2019


Ответы (4)


Это регулярное выражение позаботится о вашем отсутствующем = ? в исходной строке,

([a-zA-Z]+)\s*(?:(,)|$)

При замене на \1 = ?\2, но для обрезки лишних пробелов перед запятой вам понадобится другое регулярное выражение +,, которое будет заменено на ,, поэтому вы можете использовать эту множественную замену в php с этим кодом,

$var = "one, two , three = ?, four = 'val', five  , six = 1, seven, eight = 'val' , nine";
echo preg_replace(['/([a-zA-Z]+)\s*(?:(,)|$)/i', '/ +,/i'], ['\1 = ?\2', ','], $var);

Что дает желаемый результат,

one = ?, two = ?, three = ?, four = 'val', five = ?, six = 1, seven = ?, eight = 'val', nine = ?
person Pushpesh Kumar Rajwanshi    schedule 11.01.2019

Это почти там действительно.

  • Вам просто нужно * в качестве квантификатора для пространства вместо ?.

  • В идеале не используйте \w для сопоставления ключей, потому что это также случайно совпадет с = 1.

  • Возможно, используйте некоторые обзоры, чтобы убедиться, что = раньше не было.

Я бы пошел на что-то вроде:

preg_replace("/ (?<= ^|,|,\s)  ([a-z]+)  (?=\s*(,|$)) /x", "$1 = ?", $var)
#                       ↑         ↑            ↑
#              preceding comma   key   following comma / end

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

person mario    schedule 11.01.2019

Другим решением может быть использование explode и array_map и используйте preg_match проверяет, не соответствует ли значение шаблону ключ = значение. Затем, если это не так, добавьте = ? к значению.

Шаблон

\w+\h*=\h*\S

Это будет соответствовать

  • \w+\h* соответствует 1+ словесным символам, за которыми следует 0+ горизонтальных пробелов
  • = Соответствовать буквально
  • \h*\S Совпадение с 0+ горизонтальными пробелами, за которыми следует соответствие не пробельному символу

Например

$var = "one, two , three = ?, four = 'val', five  , six = 1, seven, eight = 'val' , nine";

echo implode(', ', array_map(function($x){
    return preg_match('/\w+\h*=\h*\S/', $x) === 0 ? $x.' = ?' : $x;
}, array_map("trim", explode(',', $var))));

Результат

one = ?, two = ?, three = ?, four = 'val', five = ?, six = 1, seven = ?, eight = 'val', nine = ?

демонстрация Php

Без использования регулярного выражения и само имя столбца не может содержать знак равенства, вы можете использовать strpos чтобы проверить, содержит ли строка =:

$var = "one, two , three = ?, four = 'val', five  , six = 1, seven, eight = 'val' , nine";

echo implode(', ', array_map(function($x){
    return strpos($x, '=') === false ? $x.' = ?' : $x;
}, array_map("trim", explode(',', $var))));

демонстрация Php

person The fourth bird    schedule 12.01.2019

person    schedule
comment
@Dharman - я написал это быстро, просто чтобы дать ему идею. вот более короткая версия. Всегда есть более короткая версия. - person SolidSnake; 11.01.2019
comment
Вы по-прежнему можете сократить trim до вызова только один раз. array_map может быть даже лучшим выбором. - person Dharman; 11.01.2019