web-dev-qa-db-fra.com

Comment détecter les caractères non imprimables dans .NET?

Je me demande simplement s'il existe une méthode dans .NET 2.0 qui vérifie si un caractère est imprimable ou non - quelque chose comme isprint(int) de la norme C.

J'ai trouvé Char.IsControl(Char).

Cela pourrait-il être utilisé à cette fin?

39
Baldewin

Vous pouvez utiliser Char.IsControl(Char) . C'est ce que j'utilise. Vous ne souhaitez certainement pas utiliser le <0x20 parce que tout caractère non latin et la plupart des caractères non anglais seront supérieurs à 127.

38
Cranston

Si par imprimable vous voulez dire rend quelque chose - même si ce quelque chose est espace vide (espace), [nier] Char.IsControl() seul est pas suffisant pour déterminer si un caractère est imprimable .

  • Ce n'est pas suffisant même dans la plage Unicode à un octet U+0000 - U+00FF (Qui est compatible avec ASCII/ISO-8859-1), car les ASCII espaces blancs autres que le caractère espace sont également classés comme caractères de contrôle, de sorte que Char.IsControl('\t') et Char.IsControl('\n') indiquent également vrai.

  • Au-delà de la plage à un octet, il existe d'autres catégories de caractères sans rendu qui doivent être reconnues.


Une solution pour la plage Unicode à un octet U+0000 - U+00FF (Compatible avec ASCII/ISO-8859 -1) :

  // Sample input char.
  char c = (char)0x20; // space

  var isPrintable = ! Char.IsControl(c) || Char.IsWhiteSpace(c);

Une approximation d'une solution pour tout Caractères Unicode :

Malheureusement, il n'y a pas de solution simple complète:

  • Une limitation fondamentale d'un test basé sur Char est que le type Char ne peut représenter que des caractères jusqu'au point de code U+FFFF, C'est-à-dire uniquement des caractères dans ce qu'on appelle BMP (plan multilingue de base). Les caractères en dehors de BMP - avec des points de code plus élevés - doivent être représentés par deuxChar instances (dites paires de substitution).

  • La catégorie de caractères UnicodeCategory.PrivateUse, Comme son nom l'indique, n'est pas normalisée; par exemple, U+F8FF sur macOS contient le symbole Apple, alors qu'il n'est pas défini sous Windows. Donc, peut contient des caractères imprimables, et vous 'aurais à déterminer dynamiquement s'ils sont imprimables.

  • La catégorie UnicodeCategory.Format principalement contient des caractères sans rendu, mais il y a des exceptions - voir ce tablea .

    • Vous pouvez coder en dur ces exceptions pour une version donnée du standard Unicode, mais cela est fastidieux et peut devenir obsolète avec le temps.

Ainsi, le code suivant suppose que tous caractères dans UnicodeCategory.PrivateUse Et UnicodeCategory.Format Sont imprimables, ce qui signifie qu'au moins certains caractères seront mal classés.

using System;
using System.Linq;
using System.Globalization;

// ...

  // Sample input char.
  char c = (char)0x20; // space

  // The set of Unicode character categories containing non-rendering,
  // unknown, or incomplete characters.
  // !! Unicode.Format and Unicode.PrivateUse can NOT be included in
  // !! this set, because they may (private-use) or do (format)
  // !! contain at least *some* rendering characters.
  var nonRenderingCategories = new UnicodeCategory[] {
    UnicodeCategory.Control,
    UnicodeCategory.OtherNotAssigned,
    UnicodeCategory.Surrogate };

  // Char.IsWhiteSpace() includes the ASCII whitespace characters that
  // are categorized as control characters. Any other character is
  // printable, unless it falls into the non-rendering categories.
  var isPrintable = Char.IsWhiteSpace(c) ||
    ! nonRenderingCategories.Contains(Char.GetUnicodeCategory(c));
11
mklement0

En plus de Char.IsControlChar(), plusieurs autres fonctions peuvent être utilisées pour déterminer de quelle catégorie correspond une valeur de caractère donnée:

  • IsLetter()
  • IsNumber()
  • IsDigit()
  • IsLetterOrDigit()
  • IsSymbol()
  • IsPunctuation()
  • IsSeparator()
  • IsWhiteSpace()

Si vous disposez d'un fichier "traditionnel ASCII text", et que vous souhaitez utiliser les fonctions fournies, l'expression:

(Char.IsLetterOrDigit(ch) || Char.IsPunctuation(ch) || Char.IsSymbol(ch) || (ch==' '))

devrait marcher.

Maintenant, si vous travaillez avec Unicode, vous ouvrez une boîte ou des vers. Même à l'époque, le fait qu'un espace soit imprimable ou non était ouvert à l'interprétation (d'où les fonctions isprint() et isgraph()). Voir cette question et réponses connexes sur les caractères Unicode "imprimables" .

2
Jay Elston