Что нового

Функция _StringIsUTF8Format возвращает True при анализе DOS-строки

Latoid

Знающий
Сообщения
95
Репутация
11
Немного предистории. Пишу e-mail парсер, почти всё готово; остался последний затык. Парсер выдирает тело письма (одной строкой) и отсылает его в функцию определения кодировки. В функции строка сначала проверяется на Utf-8 (спасибо уважаемому amel27), если False, то на предмет одной из 4-ых ANSI кодировок - WIN, KOI, DOS, ISO. Далее, в зависимости от того, какую кодировку функция вернула, идет перевод строки в win-кодировку.
И все неплохо бы, но к сожалению, если передана DOS-строка, то проверка на UTF возвращает True, что неверно. Вот пример:


Код:
$s = FileReadLine ("dos.txt", 8)

ConsoleWrite ($s & @CRLF)
ConsoleWrite (_StringIsUTF8Format ($s) & @CRLF)

Func _StringIsUTF8Format($String)
	Local $sAsc, $sLen = StringLen($String), $sExt = $sLen
	
	For $i = 1 To $sLen
		$sAsc = Asc(StringMid($String, $i, 1))
;~ 		ConsoleWrite ($sAsc & @CRLF)
		If $sAsc > 128 then $ansi=""
		If Not BitAND($sAsc, 0x80) Then
			$sExt = 0
		ElseIf Not BitXOR(BitAND($sAsc, 0xE0), 0xC0) Then
			$sExt = 1
		ElseIf Not (BitXOR(BitAND($sAsc, 0xF0), 0xE0)) Then
			$sExt = 2
		ElseIf Not BitXOR(BitAND($sAsc, 0xF8), 0xF0) Then
			$sExt = 3
		EndIf
		
		If $i + $sExt > $sLen Then Return False
		
		For $j = $i + 1 To $i + $sExt
			$sAsc = Asc(StringMid($String, $j, 1))
			If BitXOR(BitAND($sAsc, 0xC0), 0x80) Then Return False
		Next
		
		$i += $sExt
	Next
	If IsDeclared ("ansi") Then
		Return True
	Else
		Return False
	EndIf
EndFunc ; ==> _StringIsUTF8Format



Файл dos.txt для тестов прилагаю к этому сообщению.

Можно ли как-то поправить функцию _StringIsUTF8Format, чтоб в данном примере возвращала False?

Вариант прочитать кодировку из заголовка письма не подходит, т.к. письма приходят закодированными в base64, и, естесвенно, в заголовках это и стоит.

PS Дальнейшее разбор показал, что функция неверно определяет строку только если она содержит одни только заглавные буквы в DOS - кодировке. К сожалению, у некоторых групп отправителей (в данном случае - у моряков) принято писать сообщения только в в верхнем регистре - это традиция такая.

Также если удалить лидирующие пробелы в 8-ой строке, функция опять же нормально отработает.
 

amel27

Продвинутый
Сообщения
146
Репутация
55
Re: Функция _StringIsUTF8Format возращает True при анализе DOS-строки

Latoid сказал(а):
если передана DOS-строка, то проверка на UTF возвращает True, что неверно
в общем случае DOS-строка вполне может совпасть с юникодовой, но в данном конкретном случае в UDF был баг, который исправил, так что - респект! :ok:

Код:
$s = FileReadLine ("dos.txt", 8)

ConsoleWrite ($s & @CRLF)
ConsoleWrite (_StringIsUTF8Format ($s) & @CRLF)

Func _StringIsUTF8Format($sText)
    Local $iAsc, $iExt, $iLen = StringLen($sText)

    For $i = 1 To $iLen
        $iAsc = Asc(StringMid($sText, $i, 1))
        If Not BitAND($iAsc, 0x80) Then
            ContinueLoop
        ElseIf Not BitXOR(BitAND($iAsc, 0xE0), 0xC0) Then
            $iExt = 1
        ElseIf Not (BitXOR(BitAND($iAsc, 0xF0), 0xE0)) Then
            $iExt = 2
        ElseIf Not BitXOR(BitAND($iAsc, 0xF8), 0xF0) Then
            $iExt = 3
		Else
			Return False
        EndIf

        If $i + $iExt > $iLen Then Return False

        For $j = $i + 1 To $i + $iExt
            $iAsc = Asc(StringMid($sText, $j, 1))
            If BitXOR(BitAND($iAsc, 0xC0), 0x80) Then Return False
        Next

        $i += $iExt
    Next
    Return True
EndFunc ; ==> _StringIsUTF8Format


З.Ы. там было несколько строчек не моих - не понял их назначение, поэтому просто убрал... :whistle:
 
Автор
L

Latoid

Знающий
Сообщения
95
Репутация
11
Re: Функция _StringIsUTF8Format возращает True при анализе DOS-строки

Спасибо :laugh:

amel27 сказал(а):
З.Ы. там было несколько строчек не моих - не понял их назначение, поэтому просто убрал... :whistle:

Это я от себя добавил. Смысл - если в строке одни только символы с кодом меньше 128 (т.е. латинские буквы, цифры, знаки препинания - эти коды одинаковы что для ANSI, что для UTF), то функция возращает False
 
Верх