2009-07-23 7 views
1

Une autre question concerne. Unicode, les terminaux et maintenant C# et wc. Si je vous écris ce simple morceau de codeTextWriter.ReadToEnd par rapport à Unix wc Commande

int i=0; 
    foreach(char c in Console.In.ReadToEnd()) 
    { 
    if(c!='\n') i++; 
    } 
    Console.WriteLine("{0}", i); 

et entrée seulement le caractère "€" (3 octets utf-8), wc renvoie 3 caractères (en utilisant peut-être wint_t, bien que je n'ai pas vérifié), mais ReadToEnd() renvoie 1 (un caractère). Quel est exactement le comportement de ReadToEnd dans ce cas? Comment puis-je savoir ce que fait ReadToEnd dans les coulisses? Je lance xterm initialisé avec utf-8.en.US, exécutant Linux Ubuntu et Mono.

Merci.

Répondre

3

wc et la plupart des commandes de type unix traitent des caractères en termes de type de données C char qui est généralement un entier non signé de 8 bits. wc lit simplement les octets de l'entrée standard un par un sans conversion et détermine qu'il y a 3 caractères.

.NET traite les caractères en termes de son propre type de données Char qui est un entier non signé de 16 bits et représente un caractère UTF-16. La classe console a reçu les 3 octets d'entrée, a déterminé que la console à laquelle elle est attachée est UTF-8 et les a correctement convertis en un seul caractère UTF-16 euro.

+0

Donc, question de suivi rapide. Si je devais écrire le même programme en C, en utilisant wchar ou wint_t je gaspillerais (deux fois) de l'espace. Dans ce cas, c'est trivial, parce que c'est juste 16 bits mais dans les fichiers énormes la différence est perceptible. Est-ce correct? –

+0

Cela dépend. Si vous traitez du texte en anglais, un type de caractères de 8 bits et un encodage Latin-1 ou UTF-8 prendront probablement le moins d'espace. Si vous manipulez du texte chinois ou japonais, UTF-8 sera moins efficace que les autres encodages et Latin-1 ne pourra pas représenter votre texte du tout. Pour cette utilisation, UTF-16, UCS-2 ou l'un des codages spécifiques au langage serait plus compact. Notez également qu'il est également beaucoup plus compliqué de travailler avec des encodages où les caractères ont un nombre variable d'octets. Le choix d'un codage plus compact peut ralentir le traitement de votre texte. – rpetrich

2

ReadToEnd renvoie une chaîne. Toutes les chaînes dans .NET sont Unicode. Ils ne sont pas seulement un tableau d'octets.

Apparemment, wc renvoie le nombre d'octets. Le nombre d'octets et le nombre de caractères utilisés pour être la même chose.

3

Vous devez prendre en compte le codage de caractères. Actuellement, vous ne faites que compter les octets et char s et byte s ne sont pas nécessairement de la même taille.

Encoding encoding = Encoding.UTF8; 
string s = "€"; 

int byteCount = encoding.GetByteCount(s); 
Console.WriteLine(byteCount); // prints "3" on the console 

byte[] bytes = new byte[byteCount]; 
encoding.GetBytes(s, 0, s.Length, bytes, 0); 
int charCount = encoding.GetCharCount(bytes); 
Console.WriteLine(charCount); // prints "1" on the console 
1

wc, par défaut, renvoie le nombre de lignes, de mots et d'octets dans un fichier. Si vous souhaitez renvoyer le nombre de caractères en fonction de l'encodage des paramètres régionaux actifs plutôt que simplement le nombre d'octets, vous devez regarder l'option -m ou --chars que possèdent les wc modernes.

Questions connexes