Как сгенерировать все символы в кодировке UTF-8 в.net

Мне было поручено сгенерировать все символы в наборе символов UTF-8, чтобы проверить, как система обрабатывает каждый из них. У меня нет большого опыта работы с кодировкой символов. Подход, который я собирался попробовать, состоял в том, чтобы увеличить счетчик, а затем попытаться преобразовать это число из десяти основных в его эквивалентный символ UTF-8, но до сих пор я не смог найти эффективного способа сделать это в C# 3.5.

Любые предложения будут ценны.

10 ответов

System.Net.WebClient client = new System.Net.WebClient();
string definedCodePoints = client.DownloadString(
                         "http://unicode.org/Public/UNIDATA/UnicodeData.txt");
System.IO.StringReader reader = new System.IO.StringReader(definedCodePoints);
System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
while(true) {
  string line = reader.ReadLine();
  if(line == null) break;
  int codePoint = Convert.ToInt32(line.Substring(0, line.IndexOf(";")), 16);
  if(codePoint >= 0xD800 && codePoint <= 0xDFFF) {
    //surrogate boundary; not valid codePoint, but listed in the document
  } else {
    string utf16 = char.ConvertFromUtf32(codePoint);
    byte[] utf8 = encoder.GetBytes(utf16);
    //TODO: something with the UTF-8-encoded character
  }
}

Приведенный выше код должен перебирать назначенные в настоящий момент символы Юникода. Возможно, вы захотите проанализировать файл UnicodeData локально и исправить все ошибки C#, которые я сделал.

Набор назначенных в настоящее время символов Юникода меньше, чем набор, который можно определить. Конечно, то, видите ли вы персонажа, когда вы печатаете один из них, зависит от множества других факторов, таких как шрифты и другие приложения, через которые он будет проходить, прежде чем он попадет в ваше глазное яблоко.

Там нет "UTF-8 символов". Вы имеете в виду символы Unicode или кодировку UTF-8 символов Unicode?

Преобразовать int в символ Unicode легко, при условии, конечно, что для этого кода есть отображение:

char c = (char)theNumber;

Если вам нужна кодировка UTF-8 для этого символа, это тоже не сложно:

byte[] encoded = Encoding.UTF8.GetBytes(c.ToString())

Вам нужно будет проверить стандарт Unicode, чтобы увидеть диапазоны номеров, в которых определены символы Unicode.

Даже если вы сгенерируете все символы, вы обнаружите, что это не эффективный тест. Некоторые из символов объединяют метки, что означает, что они будут объединяться со следующим символом после них - наличие строки, полной комбинирующих меток, не будет иметь большого смысла. Есть и другие особые случаи. Вам будет гораздо лучше использовать реальный текст на тех языках, которые вам нужны.

Вы можете перебор Encoding выяснить, какие кодовые точки он поддерживает. Для этого просто пройдите все возможные кодовые точки, преобразуйте их в строки и посмотрите, Encoding.GetBytes() выдает исключение или нет (после настройки Encoding.EncoderFallback в EncoderExceptionFallback).

IEnumerable<int> GetAllWritableCodepoints(Encoding encoding)
{
    encoding = Encoding.GetEncoding(encoding.WebName, new EncoderExceptionFallback(), new DecoderExceptionFallback());

    var i = -1;
    // Docs for char.ConvertFromUtf32() say that 0x10ffff is the maximum code point value.
    while (i != 0x10ffff)
    {
        i++;

        var success = false;
        try
        {
            encoding.GetByteCount(char.ConvertFromUtf32(i));
            success = true;
        }
        catch (ArgumentException)
        {
        }
        if (success)
        {
            yield return i;
        }
    }
}

Этот метод должен поддерживать обнаружение символов, представленных суррогатными парами Char в.net. Тем не менее, это очень медленно (занимает несколько минут, чтобы работать на моей машине) и, вероятно, нецелесообразно.

UTF-8 - это не набор символов - это кодировка символов, которая способна кодировать любой символ из набора символов Unicode в двоичные данные.

Не могли бы вы дать больше информации о том, что вы пытаетесь сделать? Вы можете закодировать все возможные символы Юникода (включая те, которые не выделены в данный момент), хотя, если вам нужно справиться с символами вне базовой многоязычной плоскости (то есть над U+FFFF), тогда это становится немного сложнее...

Этот код будет производить вывод в файл. Все символы для печати или нет будут там.

Encoding enc = (Encoding)Encoding.GetEncoding("utf-8").Clone();
enc.EncoderFallback = new EncoderReplacementFallback("");
char[] chars = new char[1];
byte[] bytes = new byte[16];

using (StreamWriter sw = new StreamWriter(@"C:\utf-8.txt"))
{
    for (int i = 0; i <= char.MaxValue; i++)
    {
        chars[0] = (char)i;
        int count = enc.GetBytes(chars, 0, 1, bytes, 0);

        if (count != 0)
        {
            sw.WriteLine(chars[0]);
        }
    }
}

UTF-8 - это не кодировка, это кодировка. Любое значение в Unicode может быть закодировано в UTF-8 с различной длиной байта.

Для.net символы 16-битные (это не полный набор юникода, но самый практичный), поэтому вы можете попробовать это:

 for (char i = 0; i < 65536; i++) {
     string s = "" + i;
     byte[] bytes = Encoding.UTF8.GetBytes(s);
     // do something with bytes
 }

Это даст вам все символы в наборе символов - просто убедитесь, что вы указали набор символов при указании кодировки:

var results = new ConcurrentBag<int> ();
Parallel.For (0, 10, set => {
    var encoding = Encoding.GetEncoding ("ISO-8859-1");
    var c = encoding.GetEncoder ();
    c.Fallback = new EncoderExceptionFallback ();
    var start = set * 1000;
    var end = start + 1000;
    Console.WriteLine ("Worker #{0}: {1} - {2}", set, start, end);

    char[] input = new char[1];
    byte[] output = new byte[5];
    for (int i = start; i < end; i++) {
        try {
            input[0] = (char)i;
            c.GetBytes (input, 0, 1, output, 0, true);
            results.Add (i);
        }
        catch {
        }
    }
});
var hashSet = new HashSet<int> (results);
//hashSet.Remove ((int)'\r');
//hashSet.Remove ((int)'\n');
var sorted = hashSet.ToArray ();
Array.Sort (sorted);
var charset = new string (sorted.Select (i => (char)i).ToArray ());

Код Powershell, с помощью которого я собрал строки, которые я сделал с помощью кода, предложенного Джейком, в текстовый файл длиной 256 строк.

Служебные символы создают две пустые строки, не существующие в оригинале, которые необходимо удалить в исходном текстовом файле перед обработкой Powershell, чтобы результирующий файл был создан правильно.

Я просто опубликую здесь, как должна выглядеть часть ASC2.

NUL SOH STX ETX EOT ENQ ACK BEL BS TAB LF VT FF CR SO SI DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US Space ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ ABCDEFGHIJKLMNOPQRSTU VWXYZ [ \ ] ^ _ ` abcdefghijklmnopqrstu vwxyz { | } ~ PAD HOP BPH NBH IND NEL SSA ESA HTS HTJ VTS PLD PLU RI SS2 SS3 DCS PU1 PU2 STS CCH MW SPA EPA SOS SGCI SCI CSI ST OSC PM APC Non-breakingSpace ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý ã å à æ æ æ á â è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

В исходном файле каждый символ будет на новой строке.

Для просмотра служебных символов лучше использовать Notepad++. Их лучше заменить текстом своими руками.

Содержится еще два служебных символа, чуть ниже части asc2 и в конце - много.

Но, чтобы полюбоваться цветными смайликами, можно просто скопировать понравившийся текст в Word или социальную сеть. Word интерпретирует символы лучше, чем блокнот, но хуже, чем веб-сайт.

      $arrayFromFile = [IO.File]::ReadAllLines('C:\utf-8.txt')
$counter = [pscustomobject] @{ Value = 0 }
$groupSize = 256
$text=''
$groups = $arrayFromFile | Group-Object -Property { [math]::Floor($counter.Value++ / $groupSize) }
foreach ($group in $groups){
    $text+=$group.Group -join (' ')
    $text+="`n"
}
$text | Out-File -FilePath 'C:\utf-8 (sorted).txt'

Как говорили другие люди, UTF / Unicode - это кодировка, а не набор символов.

Если вы просматриваете http://www.joelonsoftware.com/articles/Unicode.html это должно помочь уточнить, что такое юникод.

Другие вопросы по тегам