Что нового

Функция вычленения информации из файла с применением double переменных.

V

VitAl2013

Гость
Версия AutoIt: 3.
3.3.6.0
Описание:
Требуется создать функцию на выходе у которой будет массив.
Функция должна парсить файл, находить внутри него куски, анализировать их, заменять некоторые значения на другие. И выдавать информацию, но это обстрактно и в общих чертах.
Что она делает "по человечески": есть файл чертежа (drw), в котором присутсвуте информация о кол-ве листов в нём, о том какой размер у этих листов, и в каких единицах он записан.
Что она делает "по программе":
1. Вычленяет блоки. Делиметр "18 18 18 E1". Сохраняет их в массив.
2. В 1 элементе массива мы можем узнать только единицы измерения форматки 1 листа чертежа. Узнаем, запоминаем и удаляем этот элемент.
3. Во 2 элементе читаем что следует за x_size - это ширина форматки 1 листа, таким же образом узнаем высоту форматки (специальной рамки на чертеже) и её имя. Также из 2 элемента массива узнаем единицы измерения следующей форматки (мм или дюймы)
4. В 3 и последущих элементах нет признаков параметров x_size или y_size, но мы знаем что там идут сразу значения, просто читаем их.
Теперь как мы их читаем. Значения высоты и ширины - вещественные числа. Прошка (Это та программа которая делает чертёж) хранит их в упакованном виде. Т.е. если значение целое (в мм), то прое отдает на него 3 байта, если дробное (в INCH) - то 8 байт. Строки заканчиваются "00".
Допустим мы прочли значение высоты 2F 7A 40. Для того чтобы узнать что это за число и предназначена функция GetDoubleValue (это в коде Дельфи, смотреть в примечаниях). Она расшифровывает это проешное hex-значение до реального 420. Правила как она это делает лучше смотреть в коде Дельфи. Дело в том что записанное double значение числа 420 это "40 7A 40", но Прошка заменяет первое число на 2F или другое число. Всё это уже вычислено и выведено в функци GetDoubleValue.

Примечания:
Темы связанные с этой проблемой.
http://fsapr2000.ru/index.php?showtopic=34742 - тут я зашёл с другого конца, так сказать, и получил ответ в виде кода на Дельфи. Смотреть аттач. http://www.wikifortio.com/772603/Get_DrwSheet.7z
Также создал тему http://autoit-script.ru/index.php?topic=1441.0 - понял что пока для меня работа с double в новинку.

Вот уже мои наработки (осталось функцию GetDoubleValue переварить):

Вот собственно и функция:

Соединить их пока не получается, так как выкидывает, отписал тут: http://autoit-script.ru/index.php?topic=1480.0

Вот что получилось на 5 апреля 2010, требуется оптимизация и шлифовка:
Код:
#include <GUIListView.au3>

Dim $result[2][3]
do
$var = FileOpenDialog("Дай drw файл! Или жми Cancel для выхода.", "c:\", "Pro/E drawing (*.drw.*)", 1) ;*.drw.* - именно так - особенности Pro/Engineer
if @error then
	Exit
EndIf
drawinfo($var)
_ArrayDisplay($result, $var)
until GUIGetMsg() = -3


func drawinfo($way_to_file)
	$chFileHnd = FileOpen($way_to_file, 4)
	Do
	$chFileTxt = FileRead($way_to_file)
	until @error = 0
	
	if StringInStr(StringToBinary($chFileTxt), "6E616D65004D4D00E001756E69745F7479") > 0 then
;~ 		ConsoleWrite ("6E616D65004D4D00E001756E69745F7479 - yes"&@CRLF)
		$result[0][0]="mm"
	else 
;~ 		ConsoleWrite ("6E616D65004D4D00E001756E69745F7479 - no"&@CRLF)
	EndIf
	if StringInStr(StringToBinary($chFileTxt), "6E616D6500494E434800E001756E69745F74797065") > 0 then
;~ 		ConsoleWrite ("6E616D6500494E434800E001756E69745F74797065 - yes"&@CRLF)
		$result[0][0]="inch"
	else 
;~ 		ConsoleWrite ("6E616D6500494E434800E001756E69745F74797065 - no"&@CRLF)
	endif
		
	$p_format = StringInStr(StringToBinary($chFileTxt), "00705F666F726D617400", 0, 1)
	$next_table = StringInStr(StringToBinary($chFileTxt), "006E6578745F7461626C6500", 0, 1)
	$pf_nt = StringMid(StringToBinary($chFileTxt), $p_format, $next_table-$p_format) 
	$result_2 = StringSplit ( $pf_nt, "181818E1" , 1 )
;~ 	_ArrayDisplay($result_2, "fresh") 
	_ArrayDelete ( $result_2, 0)
	Redim $result[UBound($result_2)][3]
	
;~ 	_ArrayDisplay($result, "$result-1")
;~ 	_ArrayDelete ( $result_2, 0)

;~ 	_ArrayDisplay($result_2, "fresh-2")
	for $i = 0 to UBound($result_2)-1 step 1 
;~ 		ConsoleWrite ("$i = "&$i&@CRLF)

		if StringInStr($result_2[$i], "4D4D00") > 0 then
;~ 			ConsoleWrite ("4D4D00 mm - yes"&@CRLF)
			$result[$i+1][0]="mm"
			$e1_plus = 6
		else 
;~ 			ConsoleWrite ("4D4D00 mm - no"&@CRLF)
		EndIf
		if StringInStr($result_2[$i], "494E434800") > 0 then
;~ 			ConsoleWrite ("494E434800 inch - yes"&@CRLF)
			$result[$i+1][0]="inch"
			$e1_plus = 6;8
		else 
;~ 			ConsoleWrite ("494E434800 inch - no"&@CRLF)
		endif
		
		$e1 = StringInStr($result_2[$i], "00E3")
;~ 		ConsoleWrite ($e1 & " - " &VarGetType($e1) &@CRLF)
		
		$x1 = StringInStr($result_2[$i], "785F73697A6500") ;есть ли x_size и какая позиция у буквы x
;~ 		ConsoleWrite ($x1&@CRLF)
		if $x1>0 Then ;если она есть то
			$cx = StringSplit(StringTrimLeft($result_2[$i], $x1+13), "E0", 1); удалив $a1+13 число символов слева элемента $result_2[0] разобъём его на элементы по делиметру E0
	;~ 		_ArrayDisplay($c, "c") 
			$result [$i][1] = _normalize_double(StringRight($cx[1], $e1_plus))
	;~ 		$result [1][0] = $b1
;~ 			ConsoleWrite($result [$i][0] & @CR)
		else
			$result [$i][1] = _normalize_double(StringMid( $result_2[$i], $e1+6, $e1_plus))
		EndIf
		
		$y1 = StringInStr($result_2[$i], "795F73697A6500") ;есть ли y_size и какая позиция у буквы y
		if $y1>0 Then ;если она есть то
			$cy = StringSplit(StringTrimLeft($result_2[$i], $y1+13) , "E0", 1); удалив $a1+13 число символов слева элемента $result_2[0] разобъём его на элементы по делиметру E0
	;~ 		_ArrayDisplay($c, "c") 
			$result [$i][2] = _normalize_double(StringRight($cy[1], $e1_plus))
	;~ 		$result [1][0] = $b1
;~ 			ConsoleWrite($result [$i][0] & @CR)
		Else
			$result [$i][2] = _normalize_double(StringMid( $result_2[$i], $e1+12, $e1_plus))
		EndIf
		
		
		
	next

	$result[0][1] = UBound($result_2)-1
	$result[0][2] = "lists"
;~ 	_ArrayDisplay($result_2, "result_2")
;~ check-begin
	$chFileTxt2= StringReplace($chFileTxt, "PicturePrimdata#", "")
	$NumberOfLists = @extended/2
	if $result[0][1]<>$NumberOfLists Then
		MsgBox (64, "Error $result[0][0]<>$NumberOfLists", "Possible error in list number ")
	EndIf
;~ check-end
;~ 	MsgBox (64, "$p_format", $pf_nt)
;~ 	" next_table "="006E6578745F7461626C6500"
;~ 	" p_format " = "00705F666F726D617400"
;~ 	"x_size " = "785F73697A6500"
;~ 	"y_size " = "795F73697A6500"
EndFunc

Func _normalize_double($hex)
	Local $result
	$f_00 = False
	$fhex = ""
	$plus = stringleft ($hex, 2)
	$cplus = ''
	if $plus <= "23" then
		$cplus = "3E"
	ElseIf $plus >= "28" and $plus <= "2C" then 
		$cplus = "3F"
	ElseIf $plus >= "2D" and $plus <= "3F" then
		$cplus = "40"
		if $plus = "2F" then
			$f_00 = True
		EndIf
	ElseIf $plus >= "4A" and $plus <= "4C" then
		$cplus = BinaryToString(Hex(Dec($cplus)+101, 2))&"3F"
	ElseIf $plus = "4D" then
		$cplus = BinaryToString(Hex(Dec($cplus)+104, 2))&"3F"
	ElseIf $plus >= "4E" and $plus <= "53" then
		$cplus = BinaryToString(Hex(Dec($cplus)+114, 2))&"3F"
	ElseIf $plus >= "54" and $plus <= "57" then
		$cplus = BinaryToString(Hex(Dec($cplus)+115, 2))&"3F"
	ElseIf $plus >= "58" and $plus <= "59" then
		$cplus = BinaryToString(Hex(Dec($cplus)+116, 2))&"3F"
	ElseIf $plus >= "5A" and $plus <= "8A" then
		$cplus = BinaryToString(Hex(Dec($cplus)+117, 2))&"3F"
	ElseIf $plus >= "8B" and $plus <= "9F" then
		$cplus = BinaryToString(Hex(Dec($cplus)-139, 2))&"40"
	ElseIf $plus = "A0" then
		$cplus = "1540"
	ElseIf $plus = "A1" then
		$cplus = "1640"
	ElseIf $plus = "A2" then
		$cplus = "1740"
	ElseIf $plus >= "A3" and $plus <= "AF" then
		$cplus = "1840"
	EndIf
;~ 	ConsoleWrite("1) "&$cplus&@CRLF)
		
	if StringLen($hex)>14 then 
;~ 		ConsoleWrite("2) "&$hex&@CRLF)
		$hex = StringRight($hex, 14)
;~ 		ConsoleWrite("3) "&$hex&@CRLF)
	EndIf
	
	For $i = StringLen($hex) - 1 To 3 Step -2
		$fhex &= StringMid($hex, $i, 2)
	Next
;~ 	ConsoleWrite("4) "&$fhex&@CRLF)

	$fhex &= $cplus
;~ 	ConsoleWrite("5) "&$fhex&@CRLF)
	
	if StringLen($fhex)<=16 then
		if $f_00 then
			for $a = 16-StringLen($fhex) to 2 step -2
				$fhex = Stringleft($fhex, 2)&$fhex
;~ 				ConsoleWrite("5.1) "&$fhex &" Length:"&stringlen($fhex)& @CR); проверить тут
			next
			
		else
			for $a = 16-StringLen($fhex) to 1 step -1
				$fhex = "0"&$fhex
			next
		EndIf
		$fhex = "0x"&$fhex
	else
;~ 		ConsoleWrite("It's bigger than 16 digits" & @CR)
		$fhex = ""
	endif
;~ 	ConsoleWrite("6) "&$fhex&@CRLF)
	
	$result = _Decode($fhex)
;~ 	ConsoleWrite("7) "&$result&@CRLF)
	
	if $hex = "07" then
		$result = 0.001
	ElseIf $hex = "09" then
		$result = 0.005
	ElseIf $hex = "0A" then
		$result = 0.01
	ElseIf $hex = "0D" then
		$result = 0.25
	ElseIf $hex = "0E" then
		$result = 0.5
	ElseIf $hex = "0F" then
		$result = 1
	ElseIf $hex = "18" then
		$result = "0"
	ElseIf $hex = "000C9A" then
		$result = "0,1"
	EndIf
	return $result
EndFunc

Func _Decode($bValue)
	$bValue = Binary($bValue)
    Local $tStruct1, $tStruct2

;~ 	ConsoleWrite("8) "&$bValue&@CRLF)
    $tStruct1 = DllStructCreate('uint64')
;~ 	ConsoleWrite("9) "&$tStruct1&@CRLF)
    DllStructSetData($tStruct1, 1, $bValue)
    $tStruct2 = DllStructCreate('double', DllStructGetPtr($tStruct1))
;~ 	ConsoleWrite("10) "&$tStruct2&@CRLF)
    Return DllStructGetData($tStruct2, 1)
EndFunc
 
Верх