Что нового

Данные, строки Отфильтровать строку от мусора

musicstashall

Знающий
Сообщения
322
Репутация
7
Имеется бинарная строка, в которой присутствуют различные SOH, EOT, SO, DC1, DC2... и прочие ненужные Управляющие символы, кроме LF и CR разумеется. Строку нужно порезать в массив по нулевым байтам (NUL - Chr(0)), плюс потом каждую подстроку еще по символам SOH - Chr(1), чтобы получить массив чистых строк. Если в строке остаются только числа, удаляем строку, если остается один символ, тоже удаляем строку. Я топорным способом реализовал фильтрацию, но хотелось бы ускорить процесс с помощью регулярных выражений. Прошу помощи знатаков.
Код:
#include <Array.au3>
#include <WinAPIConv.au3>

Global $sBytes = '0x5303000004000300280028006D018A02437573746F6D20456C656D656E74204C617965722053657474696E6773001C0001000100070027016A0246001400000000004F4B00020001000700D7006A02460014000000000043616E63656C0003001300000005000500630116000101000003000500000000000400010007000500230064001400000000004E6577000500010007008400230064001400000000004475706C69636174650006000100070004012300640014000000000044656C6574650007000F000000000041006D01020008000D00000405004800620112000000100053696E676C65206C617965722073657474696E67730009000D00000405008C00C9001200000000004261736564206F6E3A000A0013000000D2008900950016000101000003000500000000000B000D0000040500AB00CA001200000000004C617965722049443A000C000C000000D200A7009600170000001F000D000C0000007500C300320017000000FF000E000C000600AB00C3003200170000002D3130302E30003130302E30000F000C0003009800A5003200170000002D393939393939392E3000393939393939392E3000100013000000960091003200160001010000030005000000000011000D0000040500C400C80012000000000053657474696E677320746F2074656D706C6174653A001200040001000500DA006801810000001200000013000F000000000065016D01020014000100070084007101640014000000000053657474696E67732E2E2E00150001000700040171016400140000000000526573657400160002000100050076016400120000004F7074696F6E206E616D650017000D00000405007601790012000000000044656661756C74206F7074696F6E733A0018000400010005008B016801D20000001200000019000D00000805005D02C7002C0000000400001A00020001000500700061011200000054686973207479706520697320617661696C61626C65206F6E6C7920666F722063757272656E742070726F6A6563742066696C65001B000200010005005D00610112000000456E61626C652065646974696E672028636865636B20746F20656469742063757272656E74206974656D29001C0001000700D200C40096001200040000005765696768742073657474696E67732E2E2E00'
Global $sBytes2 = '0xB00100000100000000000000FA0013014A6F696E20656E6473000B000100010007000500E000F000140000000000446F2028416C742B33290002000D0000040500BE004B001200000000004761703A0003000C0006006F00BC006400170000002D393939392E3000393939392E300004000D00000005001800ED0028000000040000050001000700050045009E00140000000000476574206D6172717565652028416C742B322900060001000700A80045004B0014000000000053686F770007000D00000005006200EF00390000000400506C616E6B73206D75737420696E7465727365637420696E73696465206D6172717565652E2054686520656E6420696E73696465206D6172717565652077696C6C206265207072657365727665642E20576974686F7574206D61727175656520746865206C6F6E67657220656E642077696C6C206265207072657365727665642E0008000D00000005000500F0001200000010004F7065726174696F6E20746172676574730009000D0000040500A700F40014000000100053657474696E67733A000A000F0000000000A000FA0002000B000D0000040500FC00F00014000000040000'
Global $sBytes3 = '0xA60100000100000000000000FA000B01786C73636E63000C0001000D0000040400EF00F000140000000400000200010007009100470064001400000000005175616E7469746965732E2E2E0003000100070091008D006400140000000000434E432E2E2E0004000D00000405000400F4001400000010004C697374696E67733A00050013000000050045008200180001010000030005000000000006000300010005001A00F0001200010000004163746976652073746F7265790007000300010005002F00F00012000100000057686F6C65206D6F64656C0008001300000005008B00820018000101000003000500000000000900010007000500B400F0001400000000005072696E74696E6720616E64206C61796F7574732E2E2E000A000D000004050071008100120000000000434E432D5772697465723A000B001300000091006D00640018000101000003000500000000000C00010006000500D100F00014000000FFFF436865636B20666F7220646F75626C65737C53656C65637420616C6C2062757420746865206C61746573742066726F6D206964656E746963616C20646F75626C657300'
Global $NameIndex = 1, $sTypeIndex = 1, $Enc = 4

_ArrayDisplay(BytesToArray($sBytes))

Func BytesToArray($sBytes, $iFlag = 1)
	Local $sStrsOld = BinaryToString($sBytes)
	Local $aStrs = StringSplit($sStrsOld, Chr(0))
	Local $aData[$aStrs[0]][3] = [[0]], $iIndex = 0
	For $i = 1 To $aStrs[0]
		If $iFlag Then
			StrFilter($aStrs[$i])
			If Not $aStrs[$i] Then ContinueLoop
		EndIf
		$iIndex += 1
		$aData[$iIndex][0] = $i
		$aData[$iIndex][1] = str(bin($aStrs[$i], 1))
	Next
	ReDim $aData[$iIndex + 1][3]
	$aData[0][0] = UBound($aData) -1
	$aData[0][1] = _WinAPI_MakeLong($NameIndex, $sTypeIndex)
	$aData[0][2] = $aStrs[0]
	Return $aData
EndFunc

Func StrFilter(ByRef $str)
	Local $SOH = StringSplit($str, Chr(1)), $Data, $st = '', $s = ''
	For $i = 1 To $SOH[0]
		$Data = StringToASCIIArray($SOH[$i])
		For $j = 0 To UBound($Data) -1
			If $j = UBound($Data) Then ExitLoop
			Switch $Data[$j]
				Case 0 To 8, 12, 14 To 31, 127, 160, 152, 256 To 1024, 1040 To 1055, 1058 To 1104, 1120 To 1167, 1170 To 8210, 8219, 8223, _
					8227 To 8229, 8231 To 8239, 8241 To 8248, 8251 To 8363, 8365 To 8469, 8471 To 8481, 8483 To 1000000
					_ArrayDelete($Data, $j)
					$j -= 1
				Case Else

			EndSwitch
		Next
		$s = StringFromASCIIArray($Data)
		If UBound($Data) And StringLen($s) > 1 Then $st &= $s
	Next
	$str = $st

	If StringIsDigit($str) Then $str = ''
	If StringIsFloat($str) Then $str = ''
EndFunc


Func str($aBinary, $encoding = $Enc)
    Return BinaryToString($aBinary, $encoding)
EndFunc

Func bin($string, $encoding = $Enc)
    Return StringToBinary($string, $encoding)
EndFunc
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
хотелось бы ускорить процесс с помощью регулярных выражений.
Можно так - подогнав регулярку под себя

Код:
$aArray1=_Get_Text($sBytes)
_ArrayDisplay($aArray1)
$aArray2=_Get_Text($sBytes2)
_ArrayDisplay($aArray2)
$aArray3=_Get_Text($sBytes3)
_ArrayDisplay($aArray3)

Func _Get_Text($sBytes)
  Local $sStrsOld = BinaryToString($sBytes)
  $sStrsOld=StringReplace($sStrsOld,Chr(0),' ')
  Return StringRegExp($sStrsOld,'(*UCP)((?:\b[\p{L}:.()]{2,}[ ()]?)+)',3)
  ; Return StringRegExp($sStrsOld,'(*UCP)((?:[()]?\b[\p{L}]{2,}[ ():.+\d]*)+)',3)
EndFunc
 
Последнее редактирование:
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
В третьем бинарнике в девятой строке вначале присутствуют "яя". Это значит, что нужно было строку разделить по символу SOH, а потом проверять на соответствие условиям.
подогнав регулярку под себя
Дружище, мне трудно будет, я регулярки ваще не освоил. Попробуй еще варианты. Пжлста)
Строку сначала сплитим по нулям, затем по SOH, потом фильтруем: пустые строки удаляем, строки с одним символом удаляем и строки, в которых нет буквенных символов, тоже удаляем. По сути, нам нужны строки с символами ANSI и UTF8

Надо отметить, что скорость возросла в тысячи!!! раз! Это очень хорошо!

Вот в таком бинарнике вообще не должно быть строк:
Код:
0xDD0000001000040064006400FA0057004672616D6520706C616E6B73000B0001000200040005000200300028000000767F02000200040035000200300028000000777F03000200040065000200300028000000787F04000200040095000200300028000000797F050002000400C50002003000280000007A7F06000200040005002A003000280000007B7F07000200040035002A003000280000007C7F08000200040065002A003000280000007D7F09000200040095002A003000280000007E7F0A0002000400C5002A003000280000007F7F0B000F00000000005500FA000200

Здесь очень много мусора:
Код:
0x8F0400000100000000000000FA00A3025265676F6C61206C6520747261766900220001000D00000005001800ED0028000000040000020001000700050048009E001400000000005072656C657661206F70657261746F72692028416C742B312900030001000700A80048004B0014000000000053656C657A696F6E610004000D00000005005F00ED002800000004000005000100070005008E009E0014000000000041637175697369736369206D6172717565652028416C742B322900060001000700A8008E004B001400000000004D6F737472610007000F0000000000AB00FA00020008000D00000405000500F4001400000010004F6262696574746976692064656C6C276F706572617A696F6E653A0009000100070005005602F0001400000000004573656775692028416C742B3329000A000D00000405008802F000140000000000000B00020001000500B500F10012001000416767697573746172652061676C69206F70657261746F7269000C000D0000041900CB006E0012000000000044697374616E7A613A000D000C0006008C00C9006400170000002D393939392E3000393939392E30000E000D00000419001701D7001200000000004F706572617265207365206C276F62626965747469766F207461676C6961206C276F70657261746F72653A000F001300000019002B01D700160001010000030005000000000010000200010005004C01F100120010004D61726361726520676C69206F70657261746F72690011000D00000419007E016E001200000000004C696E65653A001200130000008C007C016400160001010000030005000000000013000D00000419009B016E00120000000000546573746F3A0014000C0000008C009901640017000000FF0015000D0000042B00B501C6001200000000003C49443E204944204F62626965747469766F2C203C4C3E204C756E6768657A7A61204F62626965747469766F0016000D0000041900CC016E00120000000000506F7320583A001700130000008C00CA016400160001010000030005000000000018000D0000041900E8016E00120000000000506F7320593A001900130000008C00E601640016000101000003000500000000001A000D000004190004026E0012000000040044696D20466F6E742028303D64656661756C74293A001B000C0003008C000202640017000000302E30003130302E30001C000D0000041900E500D700120000000000466F726D612064656C6C612066696E652064656C6C276F62626965747469766F3A001D00130000001900F900D70016000101000003000500000000001E000200010019002002D70014000000546573746F20696E20646972657A696F6E652064656C6C61206C696E6561001F000100070005006F02F0001400040000005072656C65766120696C207069616E6F2064616C2033442028416C742B34290020000D00000419006201700012000000040053757065726669636965206469207269666572696D656E746F3A002100130000008C0060016400160001010000030005000000000022000200010019003902D700140000005461676C69617265206C65206C696E6565206469206D617263617475726100
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Вот в таком бинарнике вообще не должно быть строк
Там строка "Frame planks" подходит под условие
Пробуйте - 2 варианта
Код:
Func _Get_Text($sBytes)
  Local $sStrsOld = BinaryToString($sBytes)
  $sStrsOld=StringReplace($sStrsOld,Chr(0),' ')
  $sStrsOld=StringReplace($sStrsOld,'яя','')
  Return StringRegExp($sStrsOld,"(*UCP)((?:\d?\b[\p{L}\p{P}()<>]{2,}[ <>=()\d+]*)+)",3)
EndFunc

Func _Get_Text2($sBytes)
  Local $sStrsOld = BinaryToString($sBytes)
  $sStrsOld=StringReplace($sStrsOld,Chr(0),@CRLF)
  $sStrsOld=StringReplace($sStrsOld,'яя','')
  Return StringRegExp($sStrsOld,"(*UCP)(?m)(\b[\p{L}\p{P}()<>]{2,}.*)$",3)
EndFunc
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Второй вариант пока рулит. Благодарю.

Да, как оказалось, этот вариант ломает многострочные строки. Но в других случаях он работал чище.
Код:
Global $sBytes6 = '0x4A0200004C6179657220257320636F6E7461696E696E6720656C656D656E7428732920746F2073656C6563742069732068696464656E2E0053656C656374696F6E20636F6E7461696E7320656C656D656E74732066726F6D206D756C7469706C652073746F727973202825642073746F727973292E204973206974204F4B20746F2073656C65637420656C656D656E7473206F6E6C792066726F6D20746865206C6F776573742073746F72793F0A0A5965730953656C65637420656C656D656E74732066726F6D20746865206C6F776573742073746F72790A4E6F0953656C65637420616C6C20656C656D656E747320616E797761790A43616E63656C0943616E63656C20746865206F7065726174696F6E0043616E2073656C656374206F6E6C792066726F6D20666C6F6F7220706C616E206F722033442D77696E646F772E0053656C656374696F6E20636F6E7461696E7320656C656D656E74732066726F6D2068696464656E206C61796572733A0A0A25730A0A53686F756C64207468652068696464656E206C6179657273206265206D6164652076697369626C653F0A0A5965730953686F7773207468652068696464656E206C61796572730A4E6F0953686F7773206F6E6C7920656C656D656E747320696E2076697369626C65206C61796572730A43616E63656C0943616E63656C20746865206F7065726174696F6E00536F6D65206572726F7273206F636375726564202D20636F6E74696E756520616E797761793F0A0A2573004661696C656420746F206D616B65206C617965722025732076697369626C652E00'

Func __ArrayDisplay($array)
	ConsoleWrite('++++++++++++++++++ARRAY DISPLAY++++++++++++++++' & @CR)
	Local $size = UBound($array, 0), $str
	For $i = 0 To UBound($array) -1
		If $size == 1 Then
			ConsoleWrite('=' & @TAB & $array[$i] & @CR)
		Else
			$str = '=' & @TAB
			For $j = 1 To $size
				$str &= $array[$i][$j -1] & @TAB
			Next
			ConsoleWrite($str & @CR)
		EndIf
	Next
	ConsoleWrite('+++++++++++++++++++++++END+++++++++++++++++++++' & @CR)
EndFunc


Кроме всего, мне строки нужно получать как в UTF8, так и в ANSI, в зависимости от переменной $enc

А нельзя ли попробовать использовать вместо StringRegExp функцию StringRegExpReplace? Потому что мне желательно иметь свой массив с тремя колонками, где в первой колонке должны быть номера строк. Я бы рассмотрел оба варианта, скорость на первом месте.
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Ещё 2 варианта, первый для быстрого получения, но если многострочные строки, то ещё надо подчистить. 2-вариант - с массивом подобным вашему.
Код:
Func _Get_Text3($sBytes)
  Local $sStrsOld=BinaryToString($sBytes)
  $sStrsOld=StringRegExpReplace($sStrsOld,'(\r\n|\r|\n)','§') ; заменяем переносы любым ненужным символом,можете вставить свой, потом надо удалять в многострочных строках
  $sStrsOld=StringReplace($sStrsOld,Chr(0),@CR)
  $iIndex=@extended ; содержит количество замен
  $sStrsOld=StringRegExpReplace($sStrsOld,'(?m)^яя','')
  Return StringRegExp($sStrsOld,'(*UCP)(?m)(<?\b[\p{L}\p{P}()<>]{2,}.*)$',3)
EndFunc

Func _Get_Text4($sBytes,$iEncoding=1)
  Local $sStrsOld=BinaryToString($sBytes,$iEncoding)
  $sStrsOld=StringReplace($sStrsOld,Chr(0)&'яя',Chr(0))
  Local $aStrs=StringSplit($sStrsOld,Chr(0)),$iIndex=1,$aData[$aStrs[0]][3]
  For $i=1 To $aStrs[0]
    $aRes=StringRegExp($aStrs[$i],'(*UCP)(?s)([\p{L}\p{P}()<>]{2,}.*)',1)
    If @error=0 Then
      $aData[$iIndex][0]=$i
      $aData[$iIndex][1]=$aRes[0]
      $iIndex+=1
    EndIf
  Next
  ReDim $aData[$iIndex][3]
  $aData[0][0]=$iIndex-1
  $aData[0][1]=_WinAPI_MakeLong($NameIndex,$sTypeIndex)
  $aData[0][2]=$aStrs[0]
  Return $aData
EndFunc
 
Последнее редактирование:
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Отлично. Последний вариант забираю. Очень признателен. Добра.

ПС: первый из последних я не могу использовать, так как перенос на другую строку в оригинале используется различный — или CR или LF, поэтому тут придется всякий раз сравнивать с оригиналом. Но, вижу, что можно будет поиграть с вариантами...
Вот здесь StringRegExpReplace($sStrsOld,'(\r\n|\r|\n)','§') возможно указать символ замены в зависимости от \r или \n?
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Вот здесь StringRegExpReplace($sStrsOld,'(\r\n|\r|\n)','§') возможно указать символ замены в зависимости от \r или \n?
Это общий вариант.
В основном встречаются 3 типа файла
1 - в котором перенос \r\n - @CRLF
2 - в котором перенос \r - @CR
3 - в котором перенос \n - @LF
И эта регулярка неважно какой из этих файлов найдёт перенос и заменит его на символ, поэтому отдельно использовать не вижу смысла
Код:
StringRegExpReplace($sStrsOld,'(\r)','§')
; или
StringRegExpReplace($sStrsOld,'(\n)','§')
; или
StringRegExpReplace($sStrsOld,'(\r|\n)','§')
; не вижу смысла


В RegExp есть ещё и \R

\R - любой из символов переноса строки. [\n\f\r\v] Chr(10), Chr(11), Chr(12), Chr(13), соответствует "(?>\r\n|\n|\r)"
 

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
восстановить эти символы в строке
Я просто не понял о чём сразу речь - тогда ещё пару функций, подработайте под себя
Код:
Func _CRLF(Const ByRef $sText)
  Return StringRegExp($sText,@CRLF)? @CRLF :(StringRegExp($sText,@LF)? @LF :(StringRegExp($sText,@CR)? @CR : 'нет переноса'))
EndFunc

Func _CRLF(Const ByRef $sText)
  Local $R=StringRegExp($sText,'(\r\n|\r|\n)',1)
  Return @error ? 'нет переноса' : $R[0]
EndFunc
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Обнаружил вот, начало строки обрезает: 3D material name, empty=default. 3D + пробел обрезает. В результате некоторые строки у меня пропали. Я так понял, что регулярка наблюдает первый символ — если это цифра, то обрезает, а D остается одна и тоже обрезается. Тогда проверять нужно не один символ, а два первых символа, так как один символ и так обрезается. Нельзя ли исправить, уважаемый человек?
 

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Может быть так...
Код:
$aRes=StringRegExp($aStrs[$i],'(*UCP)(?s)([\p{L}\p{P}()<>]{2,}.*|\d\p{L} .*)',1)
 
Автор
M

musicstashall

Знающий
Сообщения
322
Репутация
7
Теперь вначале строки пропали числа: 200 OBSOLETE Angled
Поэксперементировал, вставил между цифр букву 1B0 OBSOLETE Angled, но все равно, вместе с буквой отгрызает начальные символы. Оставляю только два символа в начале 1B OBSOLETE Angled — их не удаляет. Я бы даже согласился бы с таким вариантом, что цифры вначале строки удаляет, но с буквой тоже, получается, удаляет.
Оказывается, цифры удалял и предыдущий вариант, я не заметил.
 
Последнее редактирование:
Верх