Что нового

Анализ бинарных данных с помощью рег. выражений

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
Друзья, нужна помощь "регулярщиков"... Есть некая последовательность байт (данные битмапа):

0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000...

или

0x
00000000
00000000
00000000
00000000
00000000
00000000
C4C1C100
D4CECE00
C0B8B800
00000000
...

Нужно с помощью рег. выражений определить содержит ли этот бмтмап полупрозрачные точки или нет. За это отвечает четвертый байт для каждой точки. Т.е., если хотя бы один четвертый байт из всей последовательности не равен нулю, то возвращаем 1, в противном случае - 0. В данном примере полупрозрачности нет, т.к. одни нули...

Добавлено:

Другими словами, нужен шаблон, который из вешеприведенной строки убирает каждые первые 6 символов из 8 возможных. Тогда я могу записать так:

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'
$sPattern = ?

If StringReplace(StringRegExpReplace(StringTrimLeft($sData, 2), $sPattern, ''), '0', '') Then
	ConsoleWrite('1' & @CR)
Else
	ConsoleWrite('0' & @CR)
EndIf
 

SyDr

Сидра
Сообщения
651
Репутация
158
Аналогично. Данные изначально в бинарном виде? Тогда ведь даже не надо переводить в строку.

Возвращаемое значение
@error = 0
0 - битмап не содержит полупрозрачных точек
1 - битмап содержит как минимум одну полупрозрачную точку
@error = 1
0 - входные данные не бинарные
@error = 2
0 - число байтов не кратно 4

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

MsgBox(4096, Default, F(Binary($sData)))

Func F($bData)
	If Not IsBinary($bData) Then Return SetError(1, 0, 0)
	If Mod(BinaryLen($bData), 4) <> 0 Then Return SetError(2, 0, 0)

	For $iCount = 4 To BinaryLen($bData) Step 4
		If BinaryMid($bData, $iCount, 1) <> 0x00 Then Return 1
	Next

	Return 0
EndFunc
 

MockeR

Знающий
Сообщения
101
Репутация
14
Вот мой вариант:
Код:
Local $sRes = 0
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'
$sCode = StringTrimLeft($sData, 2)
$sStart = 7
Do
	$sMid = StringMid($sCode, $sStart, 2)
	If $sMid <> 0 Then $sRes = 1
	$sStart += 8
Until $sMid = ""
ConsoleWrite($sRes & @CR)
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
Спасибо, но я просил с помощью рег. выражений (даже тему так назвал). Проверить в массиве я и сам могу, но скорость... Например битмап 128x128 содержит 16384 точек с соответствующими последствиями... Именно поэтому я и хотел использовать рег. выражения. В принципе я уже и сам составил шаблон. Вроде правильно...

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

If StringReplace(StringRegExpReplace(StringTrimLeft($sData, 2), '(.{6})(.{2})', '\2'), '0', '') Then
	ConsoleWrite('1' & @CR)
Else
	ConsoleWrite('0' & @CR)
EndIf
 

SyDr

Сидра
Сообщения
651
Репутация
158
Поменял последний 0 на 1, функция всё равно 0 возвращает.

Вот мой вариант:
Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

MsgBox(4096, Default, F($sData))

Func F($sData)
	If StringRegExp(StringTrimLeft($sData, 2), "\A(.{6}0{2})*\Z") Then Return 0
	Return 1
EndFunc
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
SyDr сказал(а):
Поменял последний 0 на 1, функция всё равно 0 возвращает.
Код:
;$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000001'

If StringReplace(StringRegExpReplace(StringTrimLeft($sData, 2), '(.{6})(.{2})', '\2'), '0', '') Then
    ConsoleWrite('1' & @CR)
Else
    ConsoleWrite('0' & @CR)
EndIf


Все работает.

:-\
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
Yashied [?]
В принципе я уже и сам составил шаблон. Вроде правильно
Так вроде правильнее:

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

If StringInStr(StringRegExpReplace($sData, '0x|(.{6})(.{2})', '\2'), '1') Then
    ConsoleWrite('1' & @CR)
Else
    ConsoleWrite('0' & @CR)
EndIf
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
StringInStr() не пойдет, т.к. не обязательно должна быть 1, любое число, отличное от 0.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
Yashied [?]
StringInStr() не пойдет, т.к. не обязательно должна быть 1, любое число, отличное от 0.
Тогда так:
Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

If Not StringRegExp(StringRegExpReplace($sData, '0x|(.{6})(.{2})', '\2'), '^0+$') Then
    ConsoleWrite('1' & @CR)
Else
    ConsoleWrite('0' & @CR)
EndIf
 

asdf8

Скриптер
Сообщения
564
Репутация
152
А если так:
Код:
$str = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'
$str = '0x0000000100000001'
$str = StringReplace($str, '0x', '')

$out = StringRegExp($str, '^(.{6}(00))+$')
ConsoleWrite('->' & $out & @CRLF)
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
Всем спасибо, сделал так:

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

If StringReplace(StringRegExpReplace($sData, '0x|(.{6})(.{2})', '\2'), '0', '') Then
	ConsoleWrite('1' & @CR)
Else
	ConsoleWrite('0' & @CR)
EndIf


И вот, для чего мне это все было нужно.

:smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
asdf8 [?]
Во, тогда и ничего другого не нужно:
Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B80000000000'

If Not StringRegExp($sData, '^(0x)?(.{6}(00))+$') Then
    ConsoleWrite('1' & @CR)
Else
    ConsoleWrite('0' & @CR)
EndIf
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
Супер! ~ в 6 раз быстрее моего варианта (хотя время и так незначительное).
 

Suppir

Продвинутый
Сообщения
967
Репутация
62
Можно еще на 5 - 10% ускорить, если сохраняющие скобки лишние убрать.

Код:
$sData = '0x000000000000000000000000000000000000000000000000C4C1C100D4CECE00C0B8B8000000000'

If Not StringRegExp($sData, '^0x(?:.{6}00)+$') Then
    ConsoleWrite('1' & @CR)
Else
    ConsoleWrite('0' & @CR)
EndIf
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 713
Да, действительно.

:ok:
 
Верх