Мне просто интересно, есть ли метод в .NET 2.0, который проверяет, является ли символ печатаемым или нет - что-то вроде isprint(int)
от стандартного C.
Я нашел Char.IsControl(Char)
.
Может ли это быть использовано для этой цели?
Мне просто интересно, есть ли метод в .NET 2.0, который проверяет, является ли символ печатаемым или нет - что-то вроде isprint(int)
от стандартного C.
Я нашел Char.IsControl(Char)
.
Может ли это быть использовано для этой цели?
Возможно, вы захотите использовать Char.IsControl(Char)
. Это то, что я использую. Вы определенно не хотите использовать метод <0x20
, потому что любой нелатинский символ и большинство неанглийских символов будут выше 127.
Если под печатным символом вы имеете в виду что-то отображает - даже если это что-то пустое (пробел), одного [отрицания] 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
в основном содержит символы без визуализации, но есть исключения - см. эту таблицу.
Таким образом, следующий код предполагает, что все символы в 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));
В дополнение к Char.IsControlChar()
есть несколько других функций, которые можно использовать для определения, к какой категории относится данное значение символа:
IsLetter()
IsNumber()
IsDigit()
IsLetterOrDigit()
IsSymbol()
IsPunctuation()
IsSeparator()
IsWhiteSpace()
Если у вас есть "традиционный текстовый файл ASCII", и вы хотите использовать предоставленные функции, выражение:
(Char.IsLetterOrDigit(ch) || Char.IsPunctuation(ch) || Char.IsSymbol(ch) || (ch==' '))
должно работать.
Теперь, если вы работаете с Unicode, вы открываете банку или червей. Даже в те времена, было ли пространство для печати или не для печати, было открыто для интерпретации (отсюда функции isprint()
и isgraph()
). См. этот связанный вопрос и ответы о "печатных" символах юникода.
private bool IsPrintableCharacter(char candidate)
{
return !(candidate < 0x20 || candidate > 127);
}