Wie können Sie Nicht-ASCII-Zeichen aus einer Zeichenfolge entfernen? (in C #)

226

Wie können Sie Nicht-ASCII-Zeichen aus einer Zeichenfolge entfernen? (in C #)

Philcruz
quelle
4
Per Antwort des sinelaw unten , wenn Sie stattdessen wollen ersetzen Nicht-ASCII - Zeichen, sehen Sie diese Antwort statt .
Bobson

Antworten:

414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);
Philcruz
quelle
19
Für diejenigen von uns, die RegEx herausgefordert hatte, würde es Ihnen etwas ausmachen, Ihr RegEx-Muster in einfachem Englisch zu schreiben. Mit anderen Worten, "das ^ macht das" usw ...
Metro Smurf
47
@Metro Smurf the ^ ist der Nicht-Operator. Es weist den regulären Ausdruck an, alles zu finden, was nicht übereinstimmt, anstatt alles, was übereinstimmt. Das \ u #### - \ u #### gibt an, welche Zeichen übereinstimmen. \ U0000- \ u007F ist das Äquivalent der ersten 255 Zeichen in utf-8 oder Unicode, die immer die ASCII-Zeichen sind. Sie stimmen also mit jedem Nicht-ASCII-Zeichen überein (wegen des Nicht) und ersetzen alles, was übereinstimmt.
Gordon Tucker
41
Der Bereich für druckbare Zeichen ist 0020-007E, für Personen, die nach regulären Ausdrücken suchen, um nicht druckbare Zeichen zu ersetzen
Mubashar
1
@ GordonTucker \ u0000- \ u007F ist das Äquivalent der ersten 127 Zeichen in utf-8 oder Unicode und NICHT der ersten 225. Siehe Tabelle
full_prog_full
4
@full_prog_full Deshalb antwortete ich mir ungefähr eine Minute später und korrigierte mich, um zu sagen, dass es 127 und nicht 255 war. :)
Gordon Tucker
125

Hier ist eine reine .NET-Lösung, die keine regulären Ausdrücke verwendet:

string inputString = "Räksmörgås";
string asAscii = Encoding.ASCII.GetString(
    Encoding.Convert(
        Encoding.UTF8,
        Encoding.GetEncoding(
            Encoding.ASCII.EncodingName,
            new EncoderReplacementFallback(string.Empty),
            new DecoderExceptionFallback()
            ),
        Encoding.UTF8.GetBytes(inputString)
    )
);

Es mag umständlich aussehen, sollte aber intuitiv sein. Es verwendet die .NET ASCII-Codierung, um eine Zeichenfolge zu konvertieren. UTF8 wird während der Konvertierung verwendet, da es jedes der ursprünglichen Zeichen darstellen kann. Es verwendet einen EncoderReplacementFallback, um jedes Nicht-ASCII-Zeichen in eine leere Zeichenfolge zu konvertieren.

bzlm
quelle
5
Perfekt! Ich verwende dies, um eine Zeichenfolge zu bereinigen, bevor ich sie in einem RTF-Dokument speichere. Sehr geschätzt. Viel einfacher zu verstehen als die Regex-Version.
Nathan Prather
21
Finden Sie es wirklich leichter zu verstehen? Für mich lenken alle Dinge, die nicht wirklich relevant sind (Fallbacks, Konvertierungen in Bytes usw.), die Aufmerksamkeit von dem ab, was tatsächlich passiert.
Bzlm
21
Es ist so, als würde man sagen, dass Schraubendreher zu verwirrend sind, also benutze ich stattdessen einfach einen Hammer.
Brandon
8
@Brandon, eigentlich macht diese Technik den Job nicht besser als andere Techniken. Die Analogie wäre also, einen einfachen alten Schraubendreher anstelle eines schicken iScrewDriver Deluxe 2000 zu verwenden. :)
bzlm
10
Ein Vorteil ist, dass ich ASCII leicht durch ISO 8859-1 oder eine andere Codierung ersetzen kann :)
Akira Yamamoto
38

Ich glaube, MonsCamus meinte:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);
Josh
quelle
1
IMHO Diese Antwort ist besser als die akzeptierte Antwort, da sie Steuerzeichen entfernt.
Dean2690
15

Wenn Sie nicht streifen möchten, sondern tatsächlich lateinische Akzente in nicht akzentuierte Zeichen konvertieren möchten, werfen Sie einen Blick auf diese Frage: Wie übersetze ich 8-Bit-Zeichen in 7-Bit-Zeichen? (dh Ü bis U)

sinelaw
quelle
Ich wusste nicht einmal, dass dies möglich ist, aber es ist eine viel bessere Lösung für mich. Ich werde diesen Link zu einem Kommentar zu der Frage hinzufügen, um anderen das Auffinden zu erleichtern. Vielen Dank!
Bobson
11

Inspiriert von Philcruz 'Regular Expression-Lösung habe ich eine reine LINQ-Lösung entwickelt

public static string PureAscii(this string source, char nil = ' ')
{
    var min = '\u0000';
    var max = '\u007F';
    return source.Select(c => c < min ? nil : c > max ? nil : c).ToText();
}

public static string ToText(this IEnumerable<char> source)
{
    var buffer = new StringBuilder();
    foreach (var c in source)
        buffer.Append(c);
    return buffer.ToString();
}

Dies ist ungetesteter Code.

Bent Rasmussen
quelle
1
Für diejenigen, die es nicht verstanden haben, ist dies eine C # 4.0 LINQ-basierte Lösung. :)
7
Wie wäre es, wenn Sie anstelle der separaten ToText () -Methode Zeile 3 von PureAscii () durch Folgendes ersetzen: return new string (source.Select (c => c <min? Null: c> max? Null: c) .ToArray ()) ;;
Agentnega
Oder vielleicht ToText als: return (neuer String (Quelle)). ToArray () - je nachdem, was am besten funktioniert. Es ist immer noch schön, ToText als Erweiterungsmethode zu haben - fließend / im Pipeline-Stil. :-)
Bent Rasmussen
Dieser Code ersetzt Nicht-ASCII-Zeichen durch ein Leerzeichen. Um sie zu return new string( source.Where( c => c >= min && c <= max ).ToArray() );
entfernen
@Foozinator Mit diesem Code können Sie angeben, durch welches Zeichen die Nicht-ASCII-Zeichen ersetzt werden sollen. Standardmäßig wird ein Leerzeichen verwendet, aber wenn es wie .PureASCII (Char.MinValue) aufgerufen wird, werden alle Nicht-ASCII-Zeichen durch '\ 0' ersetzt - was sie immer noch nicht genau entfernt, aber ähnliche Ergebnisse liefert.
Ulfius
5

keine Notwendigkeit für Regex. Verwenden Sie einfach die Codierung ...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));
rjp
quelle
5
Das funktioniert nicht. Dadurch werden keine Unicode-Zeichen entfernt, sondern durch das? Ersetzt. Charakter.
David
1
@ David ist richtig. Zumindest bekam ????nacho??ich, als ich es versuchte: たまねこnachoなちin Mono 3.4
Nacho4D
1
Sie können Ihre eigene Codierungsklasse instanziieren, die Zeichen ersetzt, anstatt sie zu ersetzen. Siehe die GetEncoding-Methode: msdn.microsoft.com/en-us/library/89856k4b(v=vs.110).aspx
kkara
4

Ich fand den folgenden leicht geänderten Bereich nützlich, um Kommentarblöcke aus einer Datenbank zu analysieren. Dies bedeutet, dass Sie nicht mit Tab- und Escape-Zeichen kämpfen müssen, die dazu führen würden, dass ein CSV-Feld verärgert wird.

parsememo = Regex.Replace(parsememo, @"[^\u001F-\u007F]", string.Empty);

Wenn Sie andere Sonderzeichen oder bestimmte Satzzeichen vermeiden möchten, überprüfen Sie die ASCII-Tabelle

MonsCamus
quelle
1
Falls jemand die anderen Kommentare nicht bemerkt hat, sind die druckbaren Zeichen tatsächlich @ "[^ \ u0020- \ u007E]". Hier ist ein Link, um die Tabelle zu sehen, wenn Sie neugierig sind: asciitable.com
scradam
3

Ich bin hierher gekommen, um nach einer Lösung für erweiterte ASCII-Zeichen zu suchen, konnte sie aber nicht finden. Das nächste, was ich gefunden habe, ist die Lösung von bzlm . Aber das funktioniert nur für ASCII-Code bis 127 (natürlich können Sie den Codierungstyp in seinem Code ersetzen, aber ich denke, es war ein bisschen komplex zu verstehen. Daher diese Version zu teilen). Hier ist eine Lösung , die für arbeitet erweiterten ASCII - Codes , dh bis zu 255 , die das ist ISO 8859-1

Es werden Nicht-ASCII-Zeichen gefunden und entfernt (größer als 255).

Dim str1 as String= "â, ??î or ôu🕧� n☁i✑💴++$-💯♓!🇪🚑🌚‼⁉4⃣od;/⏬'®;😁☕😁:☝)😁😁///😍1!@#"

Dim extendedAscii As Encoding = Encoding.GetEncoding("ISO-8859-1", 
                                                New EncoderReplacementFallback(String.empty),
                                                New DecoderReplacementFallback())

Dim extendedAsciiBytes() As Byte = extendedAscii.GetBytes(str1)

Dim str2 As String = extendedAscii.GetString(extendedAsciiBytes)

console.WriteLine(str2)
'Output : â, ??î or ôu ni++$-!‼⁉4od;/';:)///1!@#$%^yz:

Hier ist eine funktionierende Geige für den Code

Ersetzen Sie die Codierung gemäß den Anforderungen, der Rest sollte gleich bleiben.

Polynom Proton
quelle
2
Der einzige, der NUR das Ω aus dieser Zeichenfolge "Ω c ç ã" entfernt hat. Vielen Dank!
Rafael Araújo
2

Dies ist in Bezug auf die Leistung nicht optimal, aber ein ziemlich direkter Linq-Ansatz:

string strippedString = new string(
    yourString.Where(c => c <= sbyte.MaxValue).ToArray()
    );

Der Nachteil ist, dass alle "überlebenden" Zeichen zuerst in ein Array vom Typ eingefügt werden, char[]das dann weggeworfen wird, nachdem der stringKonstruktor es nicht mehr verwendet.

Jeppe Stig Nielsen
quelle
1

Ich habe diesen regulären Ausdruck verwendet:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");
Anonymer Feigling
quelle
16
Dadurch werden auch Interpunktionen entfernt, nur für den Fall, dass dies nicht das ist, was jemand möchte.
Drew Noakes
1

Ich benutze diesen regulären Ausdruck, um schlechte Zeichen in einem Dateinamen herauszufiltern.

Regex.Replace(directory, "[^a-zA-Z0-9\\:_\- ]", "")

Das sollten alle Zeichen sein, die für Dateinamen zulässig sind.

user890332
quelle
1
Nee. Siehe Path.GetInvalidPathChars und Path.GetInvalidFileNameChars . Es gibt also Zehntausende gültiger Zeichen.
Tom Blodget
Du hast recht, Tom. Eigentlich habe ich an die gebräuchlichen gedacht, aber ich habe Klammern und geschweifte Klammern sowie all diese weggelassen - ^% $ # @! & + =.
user890332