XMPP разрешил имена из реестра

Примечание: это был эксперимент, чтобы увидеть, как внутренняя кодировка UTF-8. Решение, предлагаемое vilicvane , использовать объект UTF8Encoding, инициализированный для исключения исключения при отказе декодирования, намного проще и в основном делает то же самое.


Я написал этот фрагмент кода для разграничения между UTF-8 и Windows-1252. Однако он не должен использоваться для гигантских текстовых файлов, поскольку он загружает всю вещь в память и полностью сканирует ее. Я использовал его для файлов субтитров .srt, чтобы сохранить их обратно в кодировке, в которую они были загружены.

Кодировка, данная функции как ref, должна быть 8-разрядной резервной кодировкой для использовать, если файл обнаружен как недействительный UTF-8; как правило, в системах Windows это будет Windows-1252. Это не делает ничего такого, как проверка действительных действительных диапазонов ascii, хотя и не обнаруживает UTF-16 даже по значению порядка байтов.

Теорию побитового обнаружения можно найти здесь: https://ianthehenry.com/2015/1/17/decoding-utf-8/

В принципе, диапазон бит первого байта определяет, сколько после того, как оно является частью UTF -8. Эти байты после него всегда находятся в одном и том же диапазоне бит.

/// 
///     Detects whether the encoding of the data is valid UTF-8 or ascii. If detection fails, the text is decoded using the given fallback encoding.
///     Bit-wise mechanism for detecting valid UTF-8 based on https://ianthehenry.com/2015/1/17/decoding-utf-8/
///     Note that pure ascii detection should not be trusted: it might mean the file is meant to be UTF-8 or Windows-1252 but simply contains no special characters.
/// 
/// The bytes of the text document.
/// The default encoding to use as fallback if the text is detected not to be pure ascii or UTF-8 compliant. This ref parameter is changed to the detected encoding, or Windows-1252 if the given encoding parameter is null and the text is not valid UTF-8.
/// The contents of the read file
public static String ReadFileAndGetEncoding(Byte[] docBytes, ref Encoding encoding)
{
    if (encoding == null)
        encoding = Encoding.GetEncoding(1252);
    // BOM detection is not added in this example. Add it yourself if you feel like it. Should set the "encoding" param and return the decoded string.
    //String file = DetectByBOM(docBytes, ref encoding);
    //if (file != null)
    //    return file;
    Boolean isPureAscii = true;
    Boolean isUtf8Valid = true;
    for (Int32 i = 0; i < docBytes.Length; i++)
    {
        Int32 skip = TestUtf8(docBytes, i);
        if (skip != 0)
        {
            if (isPureAscii)
                isPureAscii = false;
            if (skip < 0)
                isUtf8Valid = false;
            else
                i += skip;
        }
        // if already detected that it's not valid utf8, there's no sense in going on.
        if (!isUtf8Valid)
            break;
    }
    if (isPureAscii)
        encoding = new ASCIIEncoding(); // pure 7-bit ascii.
    else if (isUtf8Valid)
        encoding = new UTF8Encoding(false);
    // else, retain given fallback encoding.
    return encoding.GetString(docBytes);
}

/// 
/// Tests if the bytes following the given offset are UTF-8 valid, and returns
/// the extra amount of bytes to skip ahead to do the next read if it is
/// (meaning, detecting a single-byte ascii character would return 0).
/// If the text is not UTF-8 valid it returns -1.
/// 
/// Byte array to test
/// Offset in the byte array to test.
/// The amount of extra bytes to skip ahead for the next read, or -1 if the byte sequence wasn't valid UTF-8
public static Int32 TestUtf8(Byte[] binFile, Int32 offset)
{
    Byte current = binFile[offset];
    if ((current & 0x80) == 0)
        return 0; // valid 7-bit ascii. Added length is 0 bytes.
    else
    {
        Int32 len = binFile.Length;
        Int32 fullmask = 0xC0;
        Int32 testmask = 0;
        for (Int32 addedlength = 1; addedlength < 6; addedlength++)
        {
            // This code adds shifted bits to get the desired full mask.
            // If the full mask is [111]0 0000, then test mask will be [110]0 0000. Since this is
            // effectively always the previous step in the iteration I just store it each time.
            testmask = fullmask;
            fullmask += (0x40 >> addedlength);
            // Test bit mask for this level
            if ((current & fullmask) == testmask)
            {
                // End of file. Might be cut off, but either way, deemed invalid.
                if (offset + addedlength >= len)
                    return -1;
                else
                {
                    // Lookahead. Pattern of any following bytes is always 10xxxxxx
                    for (Int32 i = 1; i <= addedlength; i++)
                    {
                        // If it does not match the pattern for an added byte, it is deemed invalid.
                        if ((binFile[offset + i] & 0xC0) != 0x80)
                            return -1;
                    }
                    return addedlength;
                }
            }
        }
        // Value is greater than the start of a 6-byte utf8 sequence. Deemed invalid.
        return -1;
    }
}

2
задан Norgul 17 January 2019 в 06:51
поделиться