PHP – Удаление повторяющихся знаков препинания?

Предположим, у вас есть следующая строка: Hello... how are you!!?? I'm bored!! Hello... how are you!!?? I'm bored!!

Я хочу, чтобы везде, где это было возможно, удалялась пунктуация «спина к спине», а вопросительные знаки сохранялись в случае ситуации, подобной «!?». Отфильтрованная строка должна выглядеть следующим образом:

Hello. how are you? I'm bored!

Лучший ответ – самое сжатое решение, которое решает эту проблему. Я ожидаю, что регулярные выражения будут лучшим способом решения этого вопроса, но мои знания о регулярных выражениях очень, очень ограничены в лучшем случае, и я не знаю, как это решить. Однако я более чем умею с решениями, не относящимися к регулярному выражению. Объяснение любого кода, который вы предоставляете, – если только не дьявольски прост – тоже будет приятным.

Спасибо!

 $str = preg_replace('~[?!]{2,}~', '?', preg_replace('~([.,!?])(\\1+)~', '\\1', $str)); 

или в одном вызове preg_replace (благодаря Alix Axel)

 $str = preg_replace(array('~([.,!?])(\\1+)~', '~[?!]{2,}~'), array('\\1', '?'), $str); 

Просто перечислите всю пунктуацию, о которой вы заботитесь в фигурных скобках

UPD : обрабатывать !? просто вложите его в другое регулярное выражение

Объяснение того, что все это означает:

 preg_replace('~([.,!?])(\\1+)~', '\\1', $str) 

Выражение ([.,!?])(\\1+) означает – найти любое из .,!? только если ему предшествует хотя бы один и тот же символ \\1+ , где \\1 – ссылка на предыдущий матч, а +at least one .

И замените все это только одним символом.

Внешнее выражение [?!]{2,} означает find all ? or ! if they are at least 2 in a row find all ? or ! if they are at least 2 in a row find all ? or ! if they are at least 2 in a row и заменить его ?

вы можете использовать preg_replace:

 $a="Hello... how are you!!?? Im bored!!!!!!"; echo preg_replace("/([.!?])+/iS","$1",$a); => Hello. how are you? Im bored! 
 $string = "Hello... how are you!!?? I'm bored!!" $new_string = $string; foreach(array('.',',','?','!') as $value) { $i = ; do { $prev_string = $new_string; $string = str_replace($value . $value,$value,$string; $i++; } while ($string !== $prev_string && $i<100) } 

Это избавляет от дубликатов, но не?!?.

Я думаю, что это второе решение будет работать, сохраняя FIRST из ваших «bad_chars». Если вы хотите сохранить ПОСЛЕДНИЙ, есть решения для этого.

 <?php $string = str_split($string); $new_string = array(); $i = 0; foreach($string as $key => $char) { echo 'Processing: ' . $char . '<br />'; $prev_key = $key - 1; $prev_char = $string[$prev_key]; if($i!== 0) { if(in_array($char,$bad_chars) && in_array($prev_char,$bad_chars) ) { // do nothing } else { $new_string[] = $char; } } else { $prev_char = $char; $new_string[] = $prev_char; } $i++; } $string = implode('',$string); $new_string = implode('',$new_string); ?><br /> <?php echo $string; ?><br /> <?php echo $new_string; ?><br />