Подтвердить что ты не робот

Как определить непечатаемые символы в .NET?

Мне просто интересно, есть ли метод в .NET 2.0, который проверяет, является ли символ печатаемым или нет - что-то вроде isprint(int) от стандартного C.

Я нашел Char.IsControl(Char).

Может ли это быть использовано для этой цели?

4b9b3361

Ответ 1

Возможно, вы захотите использовать Char.IsControl(Char). Это то, что я использую. Вы определенно не хотите использовать метод <0x20, потому что любой нелатинский символ и большинство неанглийских символов будут выше 127.

Ответ 2

Если под печатным символом вы имеете в виду что-то отображает - даже если это что-то пустое (пробел), одного [отрицания] Char.IsControl() недостаточно, чтобы определить, можно ли печатать символ.

  • Этого недостаточно даже в однобайтовом диапазоне Unicode U+0000 - U+00FF (который совместим с ASCII/ISO-8859-1), потому что пробельные символы ASCII, кроме пробела, также классифицируются как управляющие символы так что Char.IsControl('\t') и Char.IsControl('\n') также сообщают об истине.

  • Помимо однобайтового диапазона, существуют другие категории символов, которые не должны отображаться.


Решение для однобайтового диапазона U+0000 - U+00FF Unicode (совместимого с ASCII/ISO-8859-1):

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

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

аппроксимация решения для всех символов Юникода:

К сожалению, простого простого решения не существует:

  • Основное ограничение теста Char -based состоит в том, что тип Char может представлять символы только до кодовой точки U+FFFF, то есть только символы в так называемой BMP (базовая многоязычная плоскость). Символы вне BMP - с более высокими кодовыми точками - должны быть представлены как два экземпляра Char (так называемые суррогатные пары).

  • Категория символов UnicodeCategory.PrivateUse, как следует из названия, не стандартизирована; например, U+F8FF в macOS содержит символ Apple, тогда как в Windows он не определен. Поэтому он может содержать печатные символы, и вам придется динамически определять, являются ли они печатными.

  • Категория UnicodeCategory.Format в основном содержит символы без визуализации, но есть исключения - см. эту таблицу.

    • Вы можете жестко закодировать эти исключения для данной версии стандарта Unicode, но это громоздко и со временем может устареть.

Таким образом, следующий код предполагает, что все символы в UnicodeCategory.PrivateUse и UnicodeCategory.Format могут быть напечатаны, что означает, что по крайней мере некоторые символы будут неправильно классифицированы.

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

Ответ 3

В дополнение к Char.IsControlChar() есть несколько других функций, которые можно использовать для определения, к какой категории относится данное значение символа:

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

Если у вас есть "традиционный текстовый файл ASCII", и вы хотите использовать предоставленные функции, выражение:

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

должно работать.

Теперь, если вы работаете с Unicode, вы открываете банку или червей. Даже в те времена, было ли пространство для печати или не для печати, было открыто для интерпретации (отсюда функции isprint() и isgraph()). См. этот связанный вопрос и ответы о "печатных" символах юникода.

Ответ 4

private bool IsPrintableCharacter(char candidate)
{
    return !(candidate < 0x20 || candidate > 127);
}