w klasie znaków
[...] tylko daszek, myślnik, slash i nawiasy kwadratowe mają specjalne znaczenie i trzeba umieścić przed nimi znak ucieczki. Czyli przykład z pierwszego posta powinien działać
Ja proponuję coś takiego:
<?php
$ret = 'ciąg znaków!!!!!
? aaaaaaaaaa?
.......';
$no = '!?.,';
$maxChars = 4;
$no = str_replace( array('^', '', '-', '[', ']'), array('^', '', '-', '[', ']'), $no );
$ret = preg_replace( '/([' . $no . '])(1{0,' . ($maxChars-1) . '})(?:1)*/i', '12', $ret );
?>
[EDIT]Już widzę co jest źle. Umieściłeś "niechciane" znaki w klasie, więc twoje wyrażenie brzmiało: "jeśli znajdziesz co najmniej 4 pod rząd obojętnie jakie znaki należące do podanej klasy znaków, to je skróć".
A chciałeś, żeby brzmiało "jeśli znajdziesz co najmniej 4 wykrzykniki pod rząd, lub co najmniej 4 pytajniki pod rząd, lub co najmniej ..., to je skróć."
Przeanalizuj sobie moje wyrażenie. Dodam tylko, że
\\1 w wyrażeniu to odwołanie wsteczne. Czyli wstawiane tam jest to, co zostało "znalezione w pierwszym nawiasie okrągłym".