#php #regex
#php #регулярное выражение
Вопрос:
Как удалить последовательные повторяющиеся запятые в php. Попробовал этот фрагмент кода. Это работает, когда перед запятой нет пробела.
<?php
$a="test, , 1, , , 245 Park Avenue, New York, NY";
$my_string = preg_replace("/, /", ",", $a);
$string=trim($my_string);
echo $string;
?>
ожидаемый вывод:
$a="test, 1, 245 Park Avenue, New York, NY";
Ответ №1:
Просто измените свое регулярное выражение на это: (?:,s*){2,}
Вы можете протестировать это здесь: https://regex101.com/r/1vFhVb/2
Подробные сведения
,s*
означает запятую, за которой следуют некоторые пробелы или нет (также включает табуляцию).(?:)
это просто группа без захвата, потому что мы хотим,s*
несколько раз, поэтому мы помещаем ее в группу без захвата, подобную этой(?:,s*)
, а затем мы можем добавить{2,}
, чтобы сказать, что мы хотим это 2 или более раз.
Затем мы заменяем его на ,
(я добавил пробел для удобства чтения).
$result = preg_replace(
'/(?:,s*){2,}/',
', ',
'test, , 1, , , 245 Park Avenue, New York, NY'
);
echo $resu<
отображает: test, 1, 245 Park Avenue, New York, NY
Редактировать (благодаря Маркусу)
Как упоминал @MarkusAO, если ваша строка многострочная, необходимо заменить s
на h
, который используется для сопоставления только горизонтальных пробелов. Это приведет к этому регулярному выражению: (?:,h*){2,}
Во-вторых, что нам делать с некоторыми запятыми в начале или в конце? Обычно как бы вы обрабатывали этот ввод?
Av. de Lavaux, 31, , , 1009 Pully, VD,
, 45, 3rd floor, , 8000 Zürich, ZH, Switzerland
Test, 8, , 41 77 800 80 80, , ,
, ,, the last test,, USA
Хотим ли мы сохранить конечную запятую в первой строке? Вероятно, нет. А запятые в начале? Может быть, не снова. В этом случае мы могли бы добавить некоторые регистры в регулярное выражение, чтобы удалить их:
- Мы будем использовать многострочную опцию с
m
флагом. Это позволит нам сопоставлять начало строки с^
и окончание строки с$
. - Мы будем использовать
x
флаг для расширенной нотации, чтобы мы могли поместить его в несколько строк для большей удобочитаемости. В этой ситуации пробелы и новые строки в регулярном выражении игнорируются. - Чтобы сопоставить запятые и пробелы в начале, это будет
^(?:h*,h*)
. Поскольку мы на самом деле не знаем, есть ли пробелы до или после запятой, мы окружаем символ запятой символомh*
. Тогда вся группа должна быть один или несколько раз, вот почему мы помещаем ее в группу без захвата с - Чтобы сопоставить запятые и пробелы в конце строки, это будет просто
(?:h*,h*) $
. Это то же самое, что и выше, но вы ставите$
после повторяющихся запятых. - Теперь, чтобы убрать повторяющиеся запятые в середине, мы будем использовать другой подход. Раньше мы искали 2 или более запятых, чтобы заменить их на одну запятую. Теперь идея немного отличается, поскольку мы должны использовать пустую строку в строке замены для начальных и конечных запятых, обработанных выше. Поэтому мы будем убирать запятые только в том случае, если они стоят перед другой запятой. Это можно сделать с помощью позитивного взгляда:
- Мы ищем запятую и несколько необязательных пробелов с
,h*
помощью . - позитивный прогноз выполняется с использованием
(?= )
синтаксиса. Мы хотим снова найти запятые и пробелы, поэтому мы поместим их внутрь, и это станет(?=,h*)
. - собираем все вместе:
,h*(?=,h*)
- Мы ищем запятую и несколько необязательных пробелов с
- Мы хотим сопоставить одно из 3 регулярных выражений. Это можно сделать с
|
помощью оператора. И если мы используемx
флаг, упомянутый выше, мы можем написать его в несколько строк и добавить комментарии для удобства чтения:^(?:h*,h*) # Leading commas | (?:h*,h*) $ # Ending commas | ,h*(?=,h*) # Commas followed by commas
Тестирование и воспроизведение: https://regex101.com/r/Gvu39h/4
PHP-код стал бы:
<?php
$pattern = <<<REGEX
/
^(?:h*,h*) # Leading commas
|
(?:h*,h*) $ # Ending commas
|
,h*(?=,h*) # Commas followed by commas
/mx
REGEX;
$input = 'Av. de Lavaux, 31, , , 1009 Pully, VD,
, 45, 3rd floor, , 8000 Zürich, ZH, Switzerland
Test, 8, , 41 77 800 80 80, , ,
, ,, the last test,, USA';
$replace = '';
echo preg_replace($pattern, $replace, $input);
Он выводит следующее:
Av. de Lavaux, 31, 1009 Pully, VD
45, 3rd floor, 8000 Zürich, ZH, Switzerland
Test, 8, 41 77 800 80 80
the last test, USA
Комментарии:
1. В случае, если у нас есть промежуточный случай с начальными и конечными запятыми в многострочных CSV-данных (что может случиться), скажем,
test,, foo, bar,n ,test,bar,,foo
,s
(любой пробел) превратит две строки в одну строку, поскольку он также соответствует вертикальным пробелам, используйтеh
только для горизонтального пробела. Пример: regex101.com/r/dqclnC/12. Привет @MarkusAO! Спасибо за эту замечательную идею. Я не думал о том, что ввод может быть многострочным. Я исправлю ответ вашим предложением.
3. Ну, вы превратили это в полноценный учебник по регулярным выражениям, не так ли, отличная работа! Что касается сохранения конечных / начальных запятых, кажется, что они будут иметь значение только с точки зрения структуры данных, о чем OP, похоже, не беспокоится.
Ответ №2:
Это может быть достигнуто с array_map
помощью , array_filter
и implode
:
<?php
$a = "test, , 1, , , 245 Park Avenue, New York, NY";
$explode = array_map(function ($e) {
return trim($e);
}, explode(',', $a));
$filter = array_filter($explode);
$string = implode(', ', $filter);
echo $string . PHP_EOL;
ВОЗВРАТ test, 1, 245 Park Avenue, New York, NY
Комментарии:
1. Хорошая идея использовать explode / implode , но вместо обрезки с помощью array_map просто используйте explode с
', '
(запятая пробел) в качестве разделителя.2. @CasimiretHippolyte У меня это было изначально, но проблема в том, что если есть последовательные запятые без пробела между ними, они не будут удалены
Ответ №3:
Если вы не хотите пересекать новые строки, которые могут быть сопоставлены s
:
,h*,[h,]*
,h*,
Сопоставьте,
необязательные горизонтальные символы пробелов и другие,
[h,]*
При необходимости повторите символьный класс, соответствующий,
символу a или горизонтальному пробелу
Демонстрация регулярных выражений
$a="test, , 1, , , 245 Park Avenue, New York, NY";
$my_string = preg_replace("/,h*,[h,]*/", ", ", $a);
echo $my_string;
Вывод
test, 1, 245 Park Avenue, New York, NY
Ответ №4:
Вы можете использовать str_replace
или explode
и implode
.
Если у вас есть строка like $a
, то вы можете просто использовать str_replace
.
$a="test, , 1, , , 245 Park Avenue, New York, NY";
$my_string = str_replace(" ,","",$a);
$string=trim($my_string);
Но если у вас есть строка like $b
, вы должны использовать implode
и explode
для создания новой строки. (Обратите внимание на запятые без начальных пробелов)
$b = "test, , 1, , ,,, 245 Park Avenue, New York, NY";
$strArray = explode(',', $b);
$myArray = [];
foreach ($strArray as $str){
if (trim($str) != null || trim($str) != ""){
$myArray[] = $str;
}
}
$myStr = implode(',', $myArray);
Ответ №5:
Возможно, это самое короткое возможное решение:
while(($b = str_replace(', ,', ',', $a)) != $a)
$a = $b;
Но это работает, только если между запятыми есть пробелы.
Комментарии:
1. Вместо сравнения самой новой строки со старой, используйте
str_replace
с ее 4-м параметром вdo...while
цикле и поставьте счетчик в качестве условия while.