Comment supprimer des caractères non ASCII d'une chaîne? (en C #)

227

Comment supprimer des caractères non ASCII d'une chaîne? (en C #)

philcruz
la source
4
Selon la réponse de Sinelaw ci - dessous , si vous souhaitez remplacer les caractères non ASCII à la place, consultez plutôt cette réponse .
Bobson

Réponses:

414
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);
philcruz
la source
19
Pour ceux d'entre nous qui ont défié RegEx, cela vous dérangerait d'écrire en anglais simple votre modèle RegEx. En d'autres termes, "le ^ fait ça", etc ...
Metro Smurf
47
@Metro Smurf the ^ est l'opérateur not. Il dit au regex de trouver tout ce qui ne correspond pas, au lieu de tout ce qui correspond. Le \ u #### - \ u #### indique quels caractères correspondent. \ U0000- \ u007F est l'équivalent des 255 premiers caractères en utf-8 ou unicode, qui sont toujours les caractères ascii. Donc, vous faites correspondre tous les caractères non ascii (à cause du non) et faites un remplacement sur tout ce qui correspond.
Gordon Tucker
41
La plage de caractères imprimables est 0020-007E, pour les personnes recherchant une expression régulière pour remplacer les caractères non imprimables
Mubashar
1
@GordonTucker \ u0000- \ u007F est l'équivilent des 127 premiers caractères en utf-8 ou unicode et PAS les 225 premiers. Voir tableau
full_prog_full
4
@full_prog_full C'est pourquoi je me suis répondu une minute plus tard en me corrigeant pour dire que c'était 127 et non 255. :)
Gordon Tucker
125

Voici une solution .NET pure qui n'utilise pas d'expressions régulières:

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

Cela peut sembler lourd, mais cela devrait être intuitif. Il utilise l'encodage ASCII .NET pour convertir une chaîne. UTF8 est utilisé lors de la conversion car il peut représenter n'importe lequel des caractères d'origine. Il utilise un EncoderReplacementFallback pour convertir tout caractère non ASCII en une chaîne vide.

bzlm
la source
5
Parfait! J'utilise ceci pour nettoyer une chaîne avant de l'enregistrer dans un document RTF. Très apprécié. Beaucoup plus facile à comprendre que la version Regex.
Nathan Prather
21
Vous trouvez vraiment plus facile à comprendre? Pour moi, tout ce qui n'est pas vraiment pertinent (repli, conversion en octets, etc.) détourne l'attention de ce qui se passe réellement.
bzlm
21
C'est un peu comme dire que les tournevis sont trop confus donc je vais juste utiliser un marteau à la place.
Brandon
8
@Brandon, en fait, cette technique ne fait pas mieux que d'autres techniques. Donc, l'analogie serait d'utiliser un tournevis ordinaire à la place d'un iScrewDriver Deluxe 2000. :)
bzlm
10
Un avantage est que je peux facilement remplacer ASCII par ISO 8859-1 ou un autre encodage :)
Akira Yamamoto
38

Je crois que MonsCamus voulait dire:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);
Josh
la source
1
IMHO Cette réponse est meilleure que la réponse acceptée car elle supprime les caractères de contrôle.
Dean2690
15

Si vous ne voulez pas supprimer, mais convertir les caractères accentués latins en caractères non accentués, jetez un œil à cette question: Comment traduire des caractères 8 bits en caractères 7 bits? (c'est-à-dire Ü à U)

sinelaw
la source
Je ne savais même pas que c'était possible, mais c'est une bien meilleure solution pour moi. Je vais ajouter ce lien à un commentaire sur la question pour le rendre plus facile à trouver pour les autres. Merci!
Bobson
11

Inspiré par la solution d'expression régulière de philcruz , j'ai créé une solution LINQ pure

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

Il s'agit d'un code non testé.

Bent Rasmussen
la source
1
Pour ceux qui ne l'ont pas compris, il s'agit d'une solution basée sur LINQ C # 4.0. :)
7
Au lieu de la méthode ToText () séparée, que diriez-vous de remplacer la ligne 3 de PureAscii () par: return new string (source.Select (c => c <min? Nil: c> max? Nil: c) .ToArray ()) ;
agentnega
Ou peut-être ToText comme: return (nouvelle chaîne (source)). ToArray () - selon ce qui fonctionne le mieux. C'est toujours agréable d'avoir ToText comme méthode d'extension - style fluide / pipeline. :-)
Bent Rasmussen
Ce code remplace les caractères non ASCII par un espace. Pour les retirer, changez Sélectionner pour Où:return new string( source.Where( c => c >= min && c <= max ).ToArray() );
Foozinator
@Foozinator Ce code vous permet de spécifier avec quel caractère remplacer les caractères non ASCII. Par défaut, il utilise un espace, mais s'il est appelé comme .PureASCII (Char.MinValue), il remplacera tous les non-ASCII par '\ 0' - ce qui ne les supprime toujours pas exactement, mais des résultats similaires.
Ulfius
5

pas besoin de regex. utilisez simplement l'encodage ...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));
rjp
la source
5
Cela ne fonctionne pas. Cela ne supprime pas les caractères unicode, il les remplace par le? personnage.
David
1
@David a raison. Au moins, j'ai eu ????nacho??quand j'ai essayé: たまねこnachoなちen mono 3.4
nacho4d
1
Vous pouvez instancier votre propre classe d'encodage qui, au lieu de remplacer les caractères, les supprime. Voir la méthode GetEncoding: msdn.microsoft.com/en-us/library/89856k4b(v=vs.110).aspx
kkara
4

J'ai trouvé la plage légèrement modifiée suivante utile pour analyser les blocs de commentaires d'une base de données, cela signifie que vous n'aurez pas à composer avec des tabulations et des caractères d'échappement qui pourraient perturber un champ CSV.

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

Si vous voulez éviter d'autres caractères spéciaux ou une ponctuation particulière, consultez le tableau ascii

MonsCamus
la source
1
Si quelqu'un n'a pas remarqué les autres commentaires, les caractères imprimables sont en fait @ "[^ \ u0020- \ u007E]". Voici un lien pour voir le tableau si vous êtes curieux: asciitable.com
scradam
3

Je suis venu ici à la recherche d'une solution pour les caractères ascii étendus, mais je ne l'ai pas trouvée. Le plus proche que j'ai trouvé est la solution de bzlm . Mais cela ne fonctionne que pour le code ASCII jusqu'à 127 (évidemment, vous pouvez remplacer le type d'encodage dans son code, mais je pense que c'était un peu complexe à comprendre. Par conséquent, partager cette version). Voici une solution qui fonctionne pour les codes ASCII étendus, c'est-à-dire jusqu'à 255, qui est l' ISO 8859-1

Il trouve et supprime les caractères non ascii (supérieurs à 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:

Voici un violon de travail pour le code

Remplacez l'encodage selon l'exigence, le reste doit rester le même.

Proton polynomial
la source
2
Le seul qui a travaillé pour supprimer UNIQUEMENT le Ω de cette chaîne "Ω c ç ã". Merci beaucoup!
Rafael Araújo
2

Ce n'est pas une performance optimale, mais une approche Linq assez simple:

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

L'inconvénient est que tous les personnages "survivants" sont d'abord placés dans un tableau de type char[]qui est ensuite jeté après que le stringconstructeur ne l'utilise plus.

Jeppe Stig Nielsen
la source
1

J'ai utilisé cette expression régulière:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");
Lâche anonyme
la source
16
Cela supprime également la ponctuation, juste au cas où ce n'est pas ce que quelqu'un veut.
Drew Noakes
1

J'utilise cette expression régulière pour filtrer les mauvais caractères dans un nom de fichier.

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

Cela devrait être tous les caractères autorisés pour les noms de fichiers.

user890332
la source
1
Nan. Voir Path.GetInvalidPathChars et Path.GetInvalidFileNameChars . Il y a donc des dizaines de milliers de caractères valides.
Tom Blodget
Tu as raison, Tom. Je pensais en fait aux plus courants, mais j'ai laissé de côté les parenthèses et les accolades ainsi que tous ces - ^% $ # @! & + =.
user890332