Jak usunąć ciągi znaków spoza ASCII? (w C #)

227

Jak usunąć ciągi znaków spoza ASCII? (w C #)

philcruz
źródło
4
Za odpowiedź sinelaw jest poniżej , jeśli zamiast chcą zastąpić znaki spoza ASCII, zobacz tę odpowiedź zamiast .
Bobson,

Odpowiedzi:

414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);
philcruz
źródło
19
Dla tych z nas, których RegEx zakwestionował, czy mógłbyś napisać swój zwykły angielski wzór RegEx? Innymi słowy, „^ robi to” itp.
Metro Smurf
47
@Metro Smurf ^ nie jest operatorem. Mówi wyrażeniu regularnemu, aby znalazł wszystko, co nie pasuje, zamiast wszystkiego, co pasuje. Znak \ u #### - \ u #### mówi, które znaki pasują. \ U0000- \ u007F jest ekwiwalentem pierwszych 255 znaków w utf-8 lub Unicode, które zawsze są znakami ascii. Więc dopasowujesz każdą postać nie ascii (z powodu nie) i zastępujesz wszystko, co pasuje.
Gordon Tucker,
41
Zakres znaków do wydrukowania to 0020-007E, dla osób szukających wyrażeń regularnych zastępujących znaki niedrukowalne
Mubashar,
1
@ GordonTucker \ u0000- \ u007F jest ekwiwalentem pierwszych 127 znaków w utf-8 lub Unicode, a NIE pierwszych 225. Patrz tabela
full_prog_full
4
@full_prog_full Dlatego odpowiedziałem sobie około minutę później, poprawiając się, twierdząc, że to 127, a nie 255. :)
Gordon Tucker
125

Oto czyste rozwiązanie .NET, które nie używa wyrażeń regularnych:

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)
    )
);

Może to wyglądać nieporęcznie, ale powinno być intuicyjne. Używa kodowania ASCII .NET do konwersji łańcucha. UTF8 jest używany podczas konwersji, ponieważ może reprezentować dowolny z oryginalnych znaków. Wykorzystuje EncoderReplacementFallback do konwersji dowolnego znaku spoza ASCII na pusty ciąg znaków.

bzlm
źródło
5
Idealny! Używam tego do czyszczenia łańcucha przed zapisaniem go w dokumencie RTF. Bardzo mile widziane. Znacznie łatwiejszy do zrozumienia niż wersja Regex.
Nathan Prather,
21
Naprawdę łatwiej to zrozumieć? Dla mnie wszystkie rzeczy, które nie są tak naprawdę istotne (awarie, konwersje do bajtów itp.) Odwracają uwagę od tego, co się naprawdę dzieje.
bzlm
21
To trochę jak powiedzenie, że śrubokręty są zbyt mylące, więc zamiast tego użyję młotka.
Brandon
8
@Brandon, w rzeczywistości ta technika nie wykonuje tej pracy lepiej niż inne techniki. Więc analogia byłaby za pomocą zwykłego śrubokręta olde zamiast fantazyjny iScrewDriver Deluxe 2000. :)
bzlm
10
Jedną z zalet jest to, że mogę łatwo zastąpić ASCII ISO 8859-1 lub innym kodowaniem :)
Akira Yamamoto
38

Wierzę, że MonsCamus miał na myśli:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);
Josh
źródło
1
IMHO Ta odpowiedź jest lepsza niż odpowiedź zaakceptowana, ponieważ usuwa znaki kontrolne.
Dean2690,
15

Jeśli nie chcesz rozbierać, ale faktycznie konwertować akcenty łacińskie na znaki nieakcentowane, spójrz na to pytanie: Jak przetłumaczyć znaki 8-bitowe na znaki 7-bitowe? (tj. Ü do U)

sinelaw
źródło
Nawet nie zdawałem sobie sprawy, że to możliwe, ale jest to dla mnie znacznie lepsze rozwiązanie. Dodaję ten link do komentarza do pytania, aby ułatwić innym osobom znalezienie. Dzięki!
Bobson,
11

Zainspirowany rozwiązaniem wyrażeń regularnych philcruz stworzyłem czyste rozwiązanie LINQ

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();
}

To jest nieprzetestowany kod.

Bent Rasmussen
źródło
1
Dla tych, którzy go nie złapali, jest to rozwiązanie oparte na C # 4.0 LINQ. :)
7
Zamiast oddzielnej metody ToText (), co powiesz na zamianę wiersza 3 PureAscii () na: return new string (source.Select (c => c <min? Nil: c> max? Nil: c) .ToArray ()) ;
agentnega
A może ToText jako: return (new string (source)). ToArray () - w zależności od tego, co działa najlepiej. Nadal miło jest mieć ToText jako metodę rozszerzenia - styl płynny / potokowy. :-)
Bent Rasmussen
Ten kod zastępuje znaki spoza ASCII spacją. Aby je usunąć, zmień Wybierz na Gdzie:return new string( source.Where( c => c >= min && c <= max ).ToArray() );
Foozinator
@Foozinator Ten kod pozwala określić, który znak ma zostać zastąpiony znakami spoza ASCII. Domyślnie używa spacji, ale jeśli nazywa się jak .PureASCII (Char.MinValue), zastąpi wszystkie nie-ASCII „\ 0” - co nadal nie jest dokładnie ich usuwaniem, ale podobne wyniki.
Ulfius
5

nie ma potrzeby wyrażenia regularnego. po prostu użyj kodowania ...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));
rjp
źródło
5
To nie działa. To nie usuwa znaków Unicode, zastępuje je znakiem? postać.
David
1
@David ma rację. Przynajmniej dostałem, ????nacho??kiedy próbowałem: たまねこnachoなちin mono 3.4
nacho4d
1
Możesz utworzyć własną klasę kodowania, która zamiast zastępować znaki, usuwa je. Zobacz metodę
GetEncoding
4

Uważam, że następujący nieco zmieniony zakres jest przydatny do analizowania bloków komentarzy z bazy danych, co oznacza, że ​​nie będziesz musiał walczyć z tabulatorami i znakami ucieczki, które spowodowałyby, że pole CSV się zdenerwowało.

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

Jeśli chcesz uniknąć innych znaków specjalnych lub określonej interpunkcji, sprawdź tabelę ascii

MonsCamus
źródło
1
W przypadku, gdy nikt nie zauważył innych komentarzy, znaki do wydruku to w rzeczywistości @ „[^ \ u0020- \ u007E]”. Oto link do tabeli, jeśli jesteś ciekawy: asciitable.com
scradam
3

Przybyłem tutaj, szukając rozwiązania dla rozszerzonych postaci ascii, ale nie mogłem go znaleźć. Najbliższe znalazłem rozwiązanie bzlm . Ale działa to tylko w przypadku kodu ASCII do 127 (oczywiście można zastąpić typ kodowania w jego kodzie, ale myślę, że było to trochę skomplikowane do zrozumienia. Dlatego udostępnianie tej wersji). Oto rozwiązanie, które działa dla rozszerzonych kodów ASCII, tj. Do 255, czyli ISO 8859-1

Wyszukuje i usuwa znaki inne niż ascii (większe niż 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:

Oto działające skrzypce dla kodu

Wymień kodowanie zgodnie z wymaganiami, reszta powinna pozostać taka sama.

Proton wielomianowy
źródło
2
Jedyny, który pracował, aby usunąć TYLKO Ω z tego ciągu „Ω c ç ã”. Dziękuję Ci bardzo!
Rafael Araújo,
2

Nie jest to optymalne pod względem wydajności, ale dość proste podejście Linq:

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

Minusem jest to, że wszystkie „ocalałe” postacie są najpierw umieszczane w tablicy typu, char[]która jest następnie wyrzucana po tym, jak stringkonstruktor przestanie z niej korzystać.

Jeppe Stig Nielsen
źródło
1

Użyłem tego wyrażenia regularnego:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");
Anonimowy tchórz
źródło
16
Usuwa to także interpunkcję, na wypadek, gdyby ktoś tego nie chciał.
Drew Noakes,
1

Używam tego wyrażenia regularnego do odfiltrowywania złych znaków w nazwie pliku.

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

To powinny być wszystkie znaki dozwolone w nazwach plików.

użytkownik890332
źródło
1
Nie. Zobacz Path.GetInvalidPathChars i Path.GetInvalidFileNameChars . Istnieją dziesiątki tysięcy prawidłowych znaków.
Tom Blodget
Masz rację, Tom. Właściwie myślałem o typowych, ale pominąłem nawiasy i nawiasy klamrowe, a także wszystkie - ^% $ # @! & + =.
user890332