Что нового

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

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Вобщем задача такая:
Есть файл специфического формата (игровой), в нём зашиты строки в формате UTF-8, но кроме символов юникода там присутствуют коды значков в игре, которые отображаются в виде картинки и мне при чтении такой строки нужно оставить этот код в HEX виде.
Например:
исходная строка: 0xEF808153656C6563742043616E7661732050616E656C
UTF-8:  Select Canvas Panel
А нужно так: {EF}{80}{81} Select Canvas Panel
Изначально я выискивал их по чёрному списку:
Код:
; функция фильтрации строк
Func _FilterBinString($b_TxtStr)
	If FileExists ($sFilter_ini) = 0 Then Return $b_TxtStr ; если файл filter.ini не существует, то возвращаем из функции исходную строку
	$aFilter_ini = IniReadSection ($sFilter_ini, "filter") ; загружаем filter.ini в массив
	$sHEXstr = Hex ($b_TxtStr) ; переобразуем бинарные данные в HEX (отрезаем 0x)
	If $sHEXstr = "09" Then Return Binary ("0x7B30397D") ; если строка состоит только из одного символа "TAB", то возвращаем его HEX код в скобках
	If $sHEXstr = "20" Then Return Binary ("0x7B32307D") ; если строка состоит только из одного символа "Пробел", то возвращаем его HEX код в скобках
	For $i=1 To $aFilter_ini[0][0] ; крутим цикл столько раз сколько элементов в секции ini файла
		If StringInStr ($sHEXstr, $aFilter_ini[$i][0]) Then ; если образец присутствует, то
			$sHEXstr = StringReplace ($sHEXstr, $aFilter_ini[$i][0], $aFilter_ini[$i][1]) ; заменяем фрагменты текста
		EndIf
	Next
	Return Binary ("0x" & $sHEXstr) ; возвращаем изменённый текст
EndFunc

filter.ini такой:
Код:
[filter]
EF8081=7B45467D7B38307D7B38317D
EF8082=7B45467D7B38307D7B38327D
EF8084=7B45467D7B38307D7B38347D
EF8085=7B45467D7B38307D7B38357D
и т.д.
Но тут возникла проблема: Фильтровать приходилось и символ переноса строки 0x0D0A, но метод StringReplace выхватывал кусок из соседнего байта и строка билась. Например:
исходная строка: 0x D0 93 D0 B0 D0 B9 20 D0 A4 D0 BE D0 BA D1 81
UTF-8: Гай Фокс

Помогите составить регексп выражаение, которое бы заменяло эти символы с учётом того что 1 байт 2 символа и не тырило по 1 символу с чужих байт.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
может я недопонял, что ты имеешь в виду, но строки 0x D0 93 D0 B0 D0 B9 20 D0 A4 D0 BE D0 BA D1 81 быть не может. вернее может, но в таком случае 0 D0 A не служит в качестве символа переноса строки. а то получается, что до переноса строки у тебя 5.5 бита, что нонсенс.
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Вот именно. в этом случае это не перенос строки, а моя функция с использованием StringReplace думает что да. И из-за этого строка получается битая и отображается некорректно. с этим я и борюсь.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
ynbIpb
я запутался. у тебя есть строка вида
Код:
$s = '0xEF808153656C6563742043616E7661732050616E656C'

ты хочешь первые три бита отделить от остальных, и заключить в фигурные скобки? а остальное декодировать из UTF8? я правильно понял задачу?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
ynbIpb,
Если я Вас правильно понял, то может так?
Код:
$bStr = '0xD093D0B0D0B920D0A4D0BED0BAD181'
$sHEXstr = Hex(Binary($bStr))
$iPos = StringInStr($sHEXstr, '0D0A')
If ($iPos And Mod($iPos, 2)) Then
	$sHEXstr = StringReplace($sHEXstr, '0D0A', '!!!!', 1)
EndIf
MsgBox(0, '', $sHEXstr)

Или так?
0:rofl:0 0D 0A 93 D0 B0 D0 B9 20 D0 A4 D0 BE D0 BA D1 0D 0A 81
Код:
$bStr = '0xD00D0A93D0B0D0B920D0A4D0BED0BAD10D0A81'
$sSearch = '0D0A'
$sReplace = '!!!!'
$sHEXstr = Hex(Binary($bStr))

For $i = 1 To StringLen($sHEXstr)
	$iPos = StringInStr($sHEXstr, $sSearch, 0, $i)
	If ($iPos And Mod($iPos, 2)) Then
		$sHEXstr = StringRegExpReplace($sHEXstr, '^(.{' & ($iPos - 1) & '})(' & $sSearch & ')(.*)$', '$1' & $sReplace & '$3')
	EndIf
Next
MsgBox(0, '', $sHEXstr)
 
Автор
ynbIpb

ynbIpb

Скриптер
Сообщения
399
Репутация
110
Kaster, у меня есть много много строк и есть чёрный список неких последовательностей байт, обычно их 3 байта подрят и стрингреплейс их нормально находит и корректно заменяет. Но есть последовательность из 2х байт, которую стрингреплейс находит, но как бы выдёргивает не из того места и это проблема.

madmasles, Гениально! Нужно было просто проверять чётная или не чётная начальная позиция. Спасибо за решение.
 
Верх