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


Odpowiedzi:


414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);

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.


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

1
IMHO Ta odpowiedź jest lepsza niż odpowiedź zaakceptowana, ponieważ usuwa znaki kontrolne.
Dean2690,


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.


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

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


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.


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ć.


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

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.