Ich stelle mir vor, ich muss die Zeichen 0-31 und 127 entfernen.
Gibt es eine Funktion oder einen Code, um dies effizient zu tun?
Ich stelle mir vor, ich muss die Zeichen 0-31 und 127 entfernen.
Gibt es eine Funktion oder einen Code, um dies effizient zu tun?
Antworten:
Wenn Ihre Tardis gerade 1963 gelandet ist und Sie nur die 7-Bit-druckbaren ASCII-Zeichen möchten, können Sie Folgendes von 0-31 und 127-255 herausreißen:
$string = preg_replace('/[\x00-\x1F\x7F-\xFF]/', '', $string);
Es stimmt mit allem in den Bereichen 0-31, 127-255 überein und entfernt es.
Sie sind in eine Whirlpool-Zeitmaschine gefallen und in den achtziger Jahren zurück. Wenn Sie eine Form von 8-Bit-ASCII haben, möchten Sie möglicherweise die Zeichen im Bereich von 128 bis 255 halten. Eine einfache Einstellung - suchen Sie einfach nach 0-31 und 127
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Ah, willkommen zurück im 21. Jahrhundert. Wenn Sie eine UTF-8-codierte Zeichenfolge haben, kann der /u
Modifikator für die Regex verwendet werden
$string = preg_replace('/[\x00-\x1F\x7F]/u', '', $string);
Dadurch werden nur 0-31 und 127 entfernt. Dies funktioniert in ASCII und UTF-8, da beide denselben Kontrollsatzbereich verwenden (wie von mgutt unten angegeben). Genau genommen würde dies ohne den /u
Modifikator funktionieren . Aber es macht das Leben leichter, wenn Sie andere Zeichen entfernen möchten ...
Wenn Sie mit Unicode arbeiten, gibt es möglicherweise viele nicht druckbare Elemente . Betrachten wir jedoch ein einfaches: NO-BREAK SPACE (U + 00A0)
In einer UTF-8-Zeichenfolge würde dies als codiert 0xC2A0
. Sie können diese bestimmte Sequenz suchen und entfernen, aber mit dem /u
Modifikator können Sie einfach \xA0
die Zeichenklasse hinzufügen :
$string = preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $string);
preg_replace ist ziemlich effizient, aber wenn Sie diesen Vorgang häufig ausführen, können Sie ein Array von Zeichen erstellen, die Sie entfernen möchten, und str_replace verwenden, wie von mgutt unten angegeben, z
//build an array we can re-use across several operations
$badchar=array(
// control characters
chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
chr(31),
// non-printing characters
chr(127)
);
//replace the unwanted chars
$str2 = str_replace($badchar, '', $str);
Intuitiv scheint dies schnell zu sein, aber es ist nicht immer der Fall. Sie sollten auf jeden Fall einen Benchmark erstellen, um zu sehen, ob Sie dadurch etwas sparen. Ich habe einige Benchmarks über eine Vielzahl von Stringlängen mit zufälligen Daten durchgeführt, und dieses Muster wurde mit PHP 7.0.12 erstellt
2 chars str_replace 5.3439ms preg_replace 2.9919ms preg_replace is 44.01% faster
4 chars str_replace 6.0701ms preg_replace 1.4119ms preg_replace is 76.74% faster
8 chars str_replace 5.8119ms preg_replace 2.0721ms preg_replace is 64.35% faster
16 chars str_replace 6.0401ms preg_replace 2.1980ms preg_replace is 63.61% faster
32 chars str_replace 6.0320ms preg_replace 2.6770ms preg_replace is 55.62% faster
64 chars str_replace 7.4198ms preg_replace 4.4160ms preg_replace is 40.48% faster
128 chars str_replace 12.7239ms preg_replace 7.5412ms preg_replace is 40.73% faster
256 chars str_replace 19.8820ms preg_replace 17.1330ms preg_replace is 13.83% faster
512 chars str_replace 34.3399ms preg_replace 34.0221ms preg_replace is 0.93% faster
1024 chars str_replace 57.1141ms preg_replace 67.0300ms str_replace is 14.79% faster
2048 chars str_replace 94.7111ms preg_replace 123.3189ms str_replace is 23.20% faster
4096 chars str_replace 227.7029ms preg_replace 258.3771ms str_replace is 11.87% faster
8192 chars str_replace 506.3410ms preg_replace 555.6269ms str_replace is 8.87% faster
16384 chars str_replace 1116.8811ms preg_replace 1098.0589ms preg_replace is 1.69% faster
32768 chars str_replace 2299.3128ms preg_replace 2222.8632ms preg_replace is 3.32% faster
Die Timings selbst beziehen sich auf 10000 Iterationen, aber was interessanter ist, sind die relativen Unterschiede. Bis zu 512 Zeichen sah ich immer, wie preg_replace gewann. Im Bereich von 1 bis 8 KB hatte str_replace eine Randkante.
Ich fand das Ergebnis interessant und habe es hier aufgenommen. Das Wichtigste ist nicht, dieses Ergebnis zu verwenden, um zu entscheiden, welche Methode verwendet werden soll, sondern um einen Benchmark mit Ihren eigenen Daten durchzuführen und dann zu entscheiden.
Viele der anderen Antworten hier berücksichtigen keine Unicode-Zeichen (z. B. öäüßйȝîûηы ე மி ᚉ ⠛). In diesem Fall können Sie Folgendes verwenden:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/u', '', $string);
Es gibt eine seltsame Klasse von Zeichen im Bereich \x80-\x9F
(knapp über dem 7-Bit-ASCII-Zeichenbereich), die technisch kontrollierte Zeichen sind, aber im Laufe der Zeit für druckbare Zeichen missbraucht wurden. Wenn Sie damit keine Probleme haben, können Sie Folgendes verwenden:
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $string);
Wenn Sie auch Zeilenvorschübe, Wagenrückläufe, Tabulatoren, nicht unterbrechende Leerzeichen und weiche Bindestriche entfernen möchten, können Sie Folgendes verwenden:
$string = preg_replace('/[\x00-\x1F\x7F-\xA0\xAD]/u', '', $string);
Beachten Sie, dass Sie für die obigen Beispiele einfache Anführungszeichen verwenden müssen .
Wenn Sie alles außer einfachen druckbaren ASCII-Zeichen entfernen möchten (alle obigen Beispielzeichen werden entfernt), können Sie Folgendes verwenden:
$string = preg_replace( '/[^[:print:]]/', '',$string);
Referenz siehe http://www.fileformat.info/info/charset/UTF-8/list.htm
'/[\x00-\x1F\x80-\xC0]/u'
lässt sie intakt; aber auch Divisions- (F7) und Multiplikationszeichen (D7).
\x7F-\x9F
?
Ab PHP 5.2 haben wir auch Zugriff auf filter_var, von dem ich keine Erwähnung gesehen habe, also dachte ich, ich würde es da rauswerfen. So verwenden Sie filter_var, um nicht druckbare Zeichen <32 und> 127 zu entfernen:
Filtern Sie ASCII-Zeichen unter 32
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
Filtern Sie ASCII-Zeichen über 127
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);
Ziehe beide aus:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH);
Sie können auch niedrige Zeichen (Zeilenumbruch, Tabulator usw.) in HTML codieren, während Sie hohe Zeichen entfernen:
$string = filter_var($input, FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_LOW|FILTER_FLAG_STRIP_HIGH);
Es gibt auch Optionen zum Entfernen von HTML, zum Bereinigen von E-Mails und URLs usw. Es gibt also viele Optionen zum Bereinigen (Daten entfernen) und sogar zur Validierung (Rückgabe false, wenn nicht gültig, anstatt stillschweigend zu entfernen).
Desinfektion: http://php.net/manual/en/filter.filters.sanitize.php
Validierung: http://php.net/manual/en/filter.filters.validate.php
Es besteht jedoch immer noch das Problem, dass FILTER_FLAG_STRIP_LOW Zeilenumbrüche und Zeilenumbrüche entfernt, die für einen Textbereich vollständig gültige Zeichen sind. Einige der Regex-Antworten sind daher manchmal noch erforderlich, z. B. nach Überprüfung Thread, ich habe vor, dies für Textbereiche zu tun:
$string = preg_replace( '/[^[:print:]\r\n]/', '',$input);
Dies scheint besser lesbar zu sein als eine Reihe von regulären Ausdrücken, die durch den numerischen Bereich entfernt wurden.
Sie können Zeichenklassen verwenden
/[[:cntrl:]]+/
das ist einfacher:
$ string = preg_replace ('/ [^ [: cntrl:]] /', '', $ string);
Alle Lösungen funktionieren teilweise, und selbst im Folgenden werden wahrscheinlich nicht alle Fälle abgedeckt. Mein Problem bestand darin, einen String in eine utf8-MySQL-Tabelle einzufügen. Die Zeichenfolge (und ihre Bytes) entsprachen alle utf8, hatten jedoch mehrere fehlerhafte Sequenzen. Ich gehe davon aus, dass die meisten von ihnen Kontrolle oder Formatierung waren.
function clean_string($string) {
$s = trim($string);
$s = iconv("UTF-8", "UTF-8//IGNORE", $s); // drop all non utf-8 characters
// this is some bad utf-8 byte sequence that makes mysql complain - control and formatting i think
$s = preg_replace('/(?>[\x00-\x1F]|\xC2[\x80-\x9F]|\xE2[\x80-\x8F]{2}|\xE2\x80[\xA4-\xA8]|\xE2\x81[\x9F-\xAF])/', ' ', $s);
$s = preg_replace('/\s+/', ' ', $s); // reduce all multiple whitespace to a single space
return $s;
}
Um das Problem weiter zu verschärfen, ist die Tabelle vs. Server vs. Verbindung vs. Rendering des Inhalts, wie hier ein wenig erwähnt
$s = preg_replace('/(\xF0\x9F[\x00-\xFF][\x00-\xFF])/', ' ', $s);
weil alle Emoji-Charaktere MySQL durcheinander brachten
Meine UTF-8-kompatible Version:
preg_replace('/[^\p{L}\s]/u','',$value);
Sie können einen regulären Express verwenden, um alles außer den Zeichen zu entfernen, die Sie behalten möchten:
$string=preg_replace('/[^A-Za-z0-9 _\-\+\&]/','',$string);
Ersetzt alles, was nicht (^) die Buchstaben AZ oder az, die Zahlen 0-9, Leerzeichen, Unterstrich, Hypen, Plus und kaufmännisches Und ist - durch nichts (dh entfernen Sie es).
preg_replace('/(?!\n)[\p{Cc}]/', '', $response);
Dadurch werden alle Steuerzeichen ( http://uk.php.net/manual/en/regexp.reference.unicode.php ) entfernt, wobei die \n
Zeilenumbruchzeichen verbleiben. Nach meiner Erfahrung sind die Steuerzeichen diejenigen, die am häufigsten die Druckprobleme verursachen.
/u
für UTF-8-Zeichen hinzugefügt . Könnten Sie bitte erklären, was der erste Teil (?!\n)
tut?
So entfernen Sie alle Nicht-ASCII-Zeichen aus der Eingabezeichenfolge
$result = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
Dieser Code entfernt alle Zeichen in den Hex-Bereichen 0-31 und 128-255, wobei nur die Hex-Zeichen 32-127 in der resultierenden Zeichenfolge verbleiben, die ich in diesem Beispiel $ result nenne.
Die Antwort von @PaulDixon ist völlig falsch , da die druckbaren erweiterten ASCII-Zeichen 128-255 entfernt werden! wurde teilweise korrigiert. Ich weiß nicht, warum er immer noch 128-255 aus einem 7-Bit-ASCII-Satz mit 127 Zeichen löschen möchte, da er nicht die erweiterten ASCII-Zeichen enthält.
Aber schließlich war es wichtig, 128-255 nicht zu löschen, da zum Beispiel chr(128)
( \x80
) das Euro-Zeichen in 8-Bit-ASCII ist und viele UTF-8-Schriftarten in Windows ein Euro-Zeichen und Android in Bezug auf meinen eigenen Test anzeigen .
Und es werden viele UTF-8-Zeichen getötet, wenn Sie die ASCII-Zeichen 128-255 aus einer UTF-8-Zeichenfolge entfernen (wahrscheinlich die Startbytes eines Multi-Byte-UTF-8-Zeichens). Also tu das nicht! Sie sind in allen derzeit verwendeten Dateisystemen völlig legal. Der einzige reservierte Bereich ist 0-31 .
Verwenden Sie stattdessen diese Option, um die nicht druckbaren Zeichen 0-31 und 127 zu löschen:
$string = preg_replace('/[\x00-\x1F\x7F]/', '', $string);
Es funktioniert in ASCII und UTF-8, da beide denselben Kontrollsatzbereich verwenden .
Die schnellste langsamere Alternative ohne reguläre Ausdrücke:
$string = str_replace(array(
// control characters
chr(0), chr(1), chr(2), chr(3), chr(4), chr(5), chr(6), chr(7), chr(8), chr(9), chr(10),
chr(11), chr(12), chr(13), chr(14), chr(15), chr(16), chr(17), chr(18), chr(19), chr(20),
chr(21), chr(22), chr(23), chr(24), chr(25), chr(26), chr(27), chr(28), chr(29), chr(30),
chr(31),
// non-printing characters
chr(127)
), '', $string);
Wenn Sie alle Leerzeichen behalten wollen \t
, \n
und \r
dann entfernen chr(9)
, chr(10)
und chr(13)
aus dieser Liste. Hinweis: Das übliche Leerzeichen ist chr(32)
so, dass es im Ergebnis bleibt. Entscheiden Sie selbst, ob Sie nicht unterbrechenden Speicherplatz entfernen möchten, chr(160)
da dies zu Problemen führen kann.
¹ Von @PaulDixon getestet und von mir selbst verifiziert.
Die markierte Antwort ist perfekt, es fehlt jedoch das Zeichen 127 (DEL), das ebenfalls nicht druckbar ist
Meine Antwort wäre
$string = preg_replace('/[\x00-\x1F\x7f-\xFF]/', '', $string);
"cedivad" löste das Problem für mich mit anhaltendem Ergebnis der schwedischen Zeichen ÅÄÖ.
$text = preg_replace( '/[^\p{L}\s]/u', '', $text );
Vielen Dank!
Für alle, die immer noch nach Möglichkeiten suchen, ohne die nicht druckbaren Zeichen zu entfernen, sondern ihnen zu entkommen, habe ich dies gemacht, um zu helfen. Fühlen Sie sich frei, es zu verbessern! Zeichen werden nach \\ x [A-F0-9] [A-F0-9] maskiert.
Rufen Sie so an:
$escaped = EscapeNonASCII($string);
$unescaped = UnescapeNonASCII($string);
<?php
function EscapeNonASCII($string) //Convert string to hex, replace non-printable chars with escaped hex
{
$hexbytes = strtoupper(bin2hex($string));
$i = 0;
while ($i < strlen($hexbytes))
{
$hexpair = substr($hexbytes, $i, 2);
$decimal = hexdec($hexpair);
if ($decimal < 32 || $decimal > 126)
{
$top = substr($hexbytes, 0, $i);
$escaped = EscapeHex($hexpair);
$bottom = substr($hexbytes, $i + 2);
$hexbytes = $top . $escaped . $bottom;
$i += 8;
}
$i += 2;
}
$string = hex2bin($hexbytes);
return $string;
}
function EscapeHex($string) //Helper function for EscapeNonASCII()
{
$x = "5C5C78"; //\x
$topnibble = bin2hex($string[0]); //Convert top nibble to hex
$bottomnibble = bin2hex($string[1]); //Convert bottom nibble to hex
$escaped = $x . $topnibble . $bottomnibble; //Concatenate escape sequence "\x" with top and bottom nibble
return $escaped;
}
function UnescapeNonASCII($string) //Convert string to hex, replace escaped hex with actual hex.
{
$stringtohex = bin2hex($string);
$stringtohex = preg_replace_callback('/5c5c78([a-fA-F0-9]{4})/', function ($m) {
return hex2bin($m[1]);
}, $stringtohex);
return hex2bin(strtoupper($stringtohex));
}
?>
Ich habe das Problem für UTF8 mit https://github.com/neitanod/forceutf8 gelöst
use ForceUTF8\Encoding;
$string = Encoding::fixUTF8($string);
Der Regex in der ausgewählten Antwort schlägt für Unicode fehl: 0x1d (mit PHP 7.4)
eine Lösung:
<?php
$ct = 'différents'."\r\n test";
// fail for Unicode: 0x1d
$ct = preg_replace('/[\x00-\x1F\x7F]$/u', '',$ct);
// work for Unicode: 0x1d
$ct = preg_replace( '/[^\P{C}]+/u', "", $ct);
// work for Unicode: 0x1d and allow line break
$ct = preg_replace( '/[^\P{C}\n]+/u', "", $ct);
echo $ct;
from: UTF 8 String entfernt alle unsichtbaren Zeichen außer Zeilenumbruch