PDA

Показать полную графическую версию : [архив - Часть 2] AutoIt скрипты


Страниц : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 [38] 39 40 41 42 43 44 45 46 47 48 49 50

Creat0R
22-11-2007, 01:44
Давняя проблема с кодировками...

Есть два критичных вопроса (один критичнее другого :) ) :

1) Возможно ли написать функцию, которая будет возвращать тип кодировки указанной строки?
К примеру, функция будет именоваться так: _StringGetEncoding(), и возвращать будет в соответствии с кодировкой: ANSI, Unicode, UTF-8, UTF-8 with signature.

2) Как перекодировать строку в UTF-8 with signature кодировку? это нужно для обработки текста разных кодировок, я так понял это единственная кодировка которая справляется с текстом на многих языках.

Дело в том, что мне нужно писать в лог файл, этот лог будет содержать данные, взяты с сети (названия ссылок, заголовок страниц и т.п), но при этом эти данные должны отображаться в моём GUI, для этого я использую функцию _UTF8ToUnicode (см. в примере далее), но когдя я пишу в файл в режиме UTF-8 with signature (FileOpen("log.txt", 129)), то данные пишутся некорректно, т.е если строка на русском, то либо пишет всё что до русских символов + русские символы (и дальше не пишет :( ), либо вообще не пишет русские символы, точно как показано в примере ниже:


;Запишем сначала в файл, чтобы получить строку в кодировке Unicode (строка может быть и в этой кодировке, но проверить я не могу(?))
$hFile = FileOpen(@ScriptDir & "\temp.txt", 34)
FileWrite($hFile, "Some [Тест.txt] and more test" & @CRLF)
FileClose($hFile)
$Line = FileRead(@ScriptDir & "\temp.txt")
FileDelete(@ScriptDir & "\temp.txt")

;Теперь пишем в лог (с UTF-8 with signature кодировкой), текст с русскими символами вообще не пишется :(
$Log_File = @ScriptDir & "\Log.txt"
WriteLog($Log_File, _Utf8ToUnicode($Line))
ShellExecute($Log_File)

Func WriteLog($sFile, $Line)
Local $hFile = FileOpen($sFile, 129)
FileWrite($hFile, $Line)
FileClose($hFile)
EndFunc

Func _Utf8ToUnicode($Utf8String)
Local $BufferSize = StringLen($Utf8String) * 2
Local $Buffer = DllStructCreate("byte[" & $BufferSize & "]")
Local $Return = DllCall("Kernel32.dll", "int", "MultiByteToWideChar", _
"int", 65001, _
"int", 0, _
"str", $Utf8String, _
"int", StringLen($Utf8String), _
"ptr", DllStructGetPtr($Buffer), _
"int", $BufferSize)
Local $UnicodeBinary = DllStructGetData($Buffer, 1)
Local $UnicodeHex1 = StringReplace($UnicodeBinary, "0x", "")
Local $UnicodeString, $UnicodeHex2, $UnicodeHex3
For $i = 1 To StringLen($UnicodeHex1) Step 4
$UnicodeHex2 = StringMid($UnicodeHex1, $i, 4)
$UnicodeHex3 = StringMid($UnicodeHex2, 3, 2) & StringMid($UnicodeHex2, 1, 2)
$UnicodeString &= ChrW(Dec($UnicodeHex3))
Next
$Buffer = 0
Return $UnicodeString
EndFunc

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

P.S
Я верю что если найдётся решение для двух этих вопросов, то все мои (и не только) проблемы связанные с кодировками будут решены.

amel27
22-11-2007, 08:33
Creat0R
Возможно ли написать функцию, которая будет возвращать тип кодировки указанной строки?в общем случае нет... хотя WinAPI и содержит функцию для проверки строки на "юникодовость", но даже она не дает абсолютно достоверного результата так как применяет некие статистические алгоритмы и не рекомендуется к использованию... собственно поэтому и придумали сигнатуры, чтобы была возможность надежно определить кодировку файла
Как перекодировать строку в UTF-8 with signature кодировку?из какой кодировки и куда?.. если из ANSI в файл то штатным FileWrite() с флагом 128... если из UTF-8 в файл, то FileWrite() с флагом 16 и предварительной записью сигнатуры в начало файла при его инициализации... или имелось ввиду что-то другое?

И еще - я так и не понял зачем тебе понадобился юникод если ты работаешь только в UTF-8? :dont-know

Creat0R
22-11-2007, 09:01
amel27,
из какой кодировки и куда?
Из неизвестной, строку получаю с разных источников, именно поэтому мне и нужна функция для определения кодировки.

А строка будет отображаться в ГУИ, и далее записываться в файл. Кстати, юникодная строка в Status Bar'е отображается некоректно, когда таже строка нормально отображается в других элементах гуи... но это не так уж важно.

зачем тебе понадобился юникод если ты работаешь только в UTF-8?
Мне он вообще не нужен, я вообще не понимаю зачем столько кодировок придумали (знаю вроде зачем, но не понимаю :) ), это строка которую я получаю (программно) с сети, кодировка там бывает разная :(

amel27
22-11-2007, 10:40
Creat0R
строку получаю с разных источниковИМХО единственный выход - копать в сторону параметров самих источников строк, к примеру для файла - сигнатура, для браузера - параметры отображаемой страницы (в меню же есть, значит можно как-то и программно получить кодировку) ну и т. д.

ADD: да, еще надо учитывать особенности API которым производится чтение строк т.е. по ходу передачи строка может неожиданно сменить свою кодировку

Мне он вообще не нужентогда зачем _Utf8ToUnicode()?.. Во-первых, твоя функция переводит не в юникод, а в обычный ANSI... Во-вторых, в качестве параметра ты подаешь вместо UTF-8 обычную (ANSI) строку поэтому часть текста, отличная от ASCII интерпретируется неверно.

З.Ы. строго говоря, UTF-8 и UTF-16 имеют одну кодировку (юникодовую) но разное двоичное представление

Maza Faka
22-11-2007, 17:17
Как создать одномерный, 24-ёх элементный массив со случайными числами от 1 до 12, которые должны каждый раз располагаться в случайном порядке, причём у каждого числа должна быть пара.
Сделал так:
#include <Array.au3>

Global $ImgArray1[12]
RandomArray($ImgArray1)

Global $ImgArray2[12]
RandomArray($ImgArray2)

Global $MainArray[1]

For $i = 0 To 11
_ArrayAdd($MainArray, $ImgArray1[$i])
_ArrayAdd($MainArray, $ImgArray2[$i])
Next

$ImgArray1 = 0
$ImgArray2 = 0

_ArrayDisplay($MainArray)

Func RandomArray(ByRef $retArray)
For $i = 0 To UBound($retArray) -1
While 1
$number = Random(1, 12, 1)
$search = _ArraySearch($retArray, $number)
If @error Then ExitLoop
WEnd
$retArray[$i] = $number
Next
EndFunc
, но получилось громоздко и некрасиво, может, кто-нибудь подкинет идею, как можно сделать покрасивее?

Creat0R
23-11-2007, 00:52
amel27,
Ок, Прикрепляю реальный пример, вывод в гуи, нормально, запись в файл - не нормально :(.

Обойти можно если использовать функцию кодировки только для показа в ГУИ, но бывают и другие строки (всё зависит от запроса поиска), которые нормально отображатся в ГУИ и без перекодировки, но в файл попадут неверно... вот и не могу найти идеальное решение... как говорится - Catch 22 (http://en.wikipedia.org/wiki/Catch-22) ;)


P.S
Этот код, это часть моего проэкта YouTube Download Center! (http://creator-lab.ucoz.ru/load/4-1-0-24) (исходники и необходимые ресурсы там прилагаются).


Maza Faka
24-ёх элементный массив со случайными числами от 1 до 12, которые должны каждый раз располагаться в случайном порядке
Кажется ты(?) уже задавал точно такой вопрос :)
И я даже пример вроде привёл (сорри, найти не удалось).

amel27
23-11-2007, 06:24
Прикрепляю реальный пример, вывод в гуи, нормально »как я себе представляю вывод в юникоде:#include <A3LConstants.au3>

; ...
; Это кусок скрипта между "Case $Get_Button" и "EndSwitch"
GUICtrlSetData($StatusLabel, "Please wait...")
$VNameUTF8 = GetName("fQyYG-1nhMA") ;Это видео ролик с YouTube (имя ролика на иврите)
$VNameUTF16= _Utf8ToUnicode($VNameUTF8) ; Возвращает тип BINARY
$struUTF16 = DllStructCreate("byte["&BinaryLen($VNameUTF16)&"];byte[2]") ; Структура для UTF-16
DllStructSetData($struUTF16, 1, $VNameUTF16) ; Заполняем структуру
GUICtrlSendMsg($Data_Input, $WM_SETTEXT, 0, DllStructGetPtr($struUTF16)) ; Устанавливаем текст контрола
WriteToLog("Video Name: [" & $VNameUTF8 & "] and data")
GUICtrlSetData($StatusLabel, "")
; ...

; Функция возвращает тип BINARY
Func _Utf8ToUnicode($UTF8String)
Local $ret = DllCall("Kernel32.dll", "int", "MultiByteToWideChar", _
"int", 65001, _
"int", 0, _
"str", $UTF8String, _
"int", -1, _
"ptr", 0, _
"int", 0)
Local $buf = DllStructCreate("byte[" & $ret[0]*2 & "]")
$ret = DllCall("Kernel32.dll", "int", "MultiByteToWideChar", _
"int", 65001, _
"int", 0, _
"str", $UTF8String, _
"int", -1, _
"ptr", DllStructGetPtr($buf), _
"int", $ret[0])
Return DllStructGetData($buf, 1)
EndFunc
запись в файл - не нормально »хм, сигнатура должна быть всего одна в начале файла, а у тебя добавляется перед каждой строкой... поэтому лучше не доверять AutoIT и сделать все самому, типа:Func WriteToLog($Line)
Local $hLogFile, $Log_File = StringTrimRight(@ScriptFullPath, 3) & "log"
Local $GetDateTime = @HOUR & ":" & @MIN & ":" & @SEC & ", " & @MDAY & "/" & @MON & "/" & @YEAR

If Not FileExists($Log_File) Then
$hLogFile = FileOpen($Log_File, 17)
FileWrite($Log_File, chr(0xEF) & chr(0xBB) & chr(0xBF) & _
"========================================================================" & @CRLF & _
"Log File for <" & @ScriptName & "> started at: " & $GetDateTime & @CRLF & _
"========================================================================" & @CRLF & @CRLF)
Else
$hLogFile = FileOpen($Log_File, 17)
EndIf

FileWrite($hLogFile, StringToBinary("[" & $GetDateTime & "]" & @CRLF,4))
FileWrite($hLogFile, StringToBinary(">> ",4) & Binary($Line) & StringToBinary(@CRLF & @CRLF,4))
FileClose($hLogFile)
EndFunc

Creat0R
23-11-2007, 08:38
amel27,
Спасибо большое!
С этим примером всё отлично работает, но на самом деле всё намного сложнее, в лог при некоторых обстоятельствах пишется и путь к файлу вместе с именем с сети (скачивается видео с сети), если путь содержит кириллицу, или теже ивритские символы (или вообще и те и другие), то в файле получается полная каша :(

А также мне будет немного сложно адаптировать подобный метод, GuiCtrlSendMsg() работает с обычными контролями, а что делать со StatusBar к примеру? (не Label) - возможно SendMessage, но опять таки, это не надёжно, StatusBar не полностью поддерживает юникод. А также обновлять данные нужно по несколько раз, в зависимости от отображаемых элементов (там у меня есть динамичная панель которая скрывается опционально)...

Кстати, есть ещё функция StringToUTF() (без API, чистая перекодировка символов), можно попробовать путь кодировать отдельно, а имя с сети отдельно... но вот если бы была функция для определения кодировки строки, то это упростило бы работу намного.

В общем спасибо ещё раз, попробую найти хоть какой то компромис.

amel27
23-11-2007, 09:22
на самом деле всё намного сложнее »в любом случае все нужно конвертить в UTF-16 так как это native-кодировка Windows
возможно SendMessage, но опять таки, это не надёжно »имхо это как раз надежней... ну, можно еще "покапать на мозги" разработчикам, может добавят в GUI-функции поддержку текста не только в ANSI, но и в UTF-16 (тип Binary)
StatusBar не полностью поддерживает юникод »можно пример?
можно попробовать путь кодировать отдельно, а имя с сети отдельно... но вот если бы была функция для определения кодировки строки »Ну не может быть такой функции (кроме частных случаев), так что единственный выход я уже озвучивал - скурпулезный учет всех источников и их раздельная кодировка... примерно так я и делал в функции WriteToLog()
есть ещё функция StringToUTF() »хм, у меня еще нет... может версию обновить?

Creat0R
23-11-2007, 13:25
amel27, можно пример?
В том скрипте что я прикрепил, замени создание строки состояния (Label) на настоящий StatusBar, и полученное имя видео отобрази в этом статус баре, всё что отобразиться так это ????????.

хм, у меня еще нет
Это самопальная функция :biggrin: - Вот:

Func StringToUTF($String)
Local $sResult = "", $iCode
Local $VarUTFArr = StringSplit($String, "")

For $i = 1 To $VarUTFArr[0]
$iCode = Asc($VarUTFArr[$i])

Select
Case $iCode >= 192 And $iCode <= 239
$VarUTFArr[$i] = Chr(208) & Chr($iCode - 48)
Case $iCode >= 240 And $iCode <= 255
$VarUTFArr[$i] = Chr(209) & Chr($iCode - 112)
Case $iCode = 168
$VarUTFArr[$i] = Chr(208) & Chr(129)
Case $iCode = 184
$VarUTFArr[$i] = Chr(209) & Chr(145)
Case Else
$VarUTFArr[$i] = Chr($iCode)
EndSelect

$sResult &= $VarUTFArr[$i]
Next

Return $sResult
EndFunc

Maza Faka
23-11-2007, 17:30
Creat0R, Кажется ты(?) уже задавал точно такой вопрос
И я даже пример вроде привёл (сорри, найти не удалось). »
Да, я уже задавал такой вопрос, но твоё решение не отвечало одному из требований задачи (сорри не могу вспомнить какому именно требованию, так, как тоже не смог найти твой пост) Если не трудно выложи своё решение ;)

Drsmog
23-11-2007, 20:06
Как выполнить такое условие если в блокноте, строке есть знак + тогда выполнить дествие ???

Creat0R
24-11-2007, 06:41
Maza Faka,
не смог найти твой пост
Google рулит (при правильном запросе: 24 +массив site:forum.oszone.net ;) )...

http://forum.oszone.net/thread-60616-164.html#post666511

Там задача была похожая, только от 1 до 13 :) ..
И массив я сделал двумерный (мне кажется так легче), но то что ты сделал в твоём примере, можно сделать двумя циклами (плюс вспомагательная функция):


#include <Array.au3> ;Только для _ArrayDisplay()

Global $MainArray = GetArray(24, 12)

_ArrayDisplay($MainArray)

Func GetArray($iElements = 24, $iRandom = 12)
Local $iRandNum, $avRetArray[$iElements + 1]

For $i = 1 To $iElements
$iRandNum = Random(1, $iRandom, 1)
If _FindInArray($avRetArray, $iRandNum) = -1 Then
$avRetArray[$i] = $iRandNum
Else
While _FindInArray($avRetArray, $iRandNum) > 1
$iRandNum = Random(1, $iRandom, 1)
WEnd
$avRetArray[$i] = $iRandNum
EndIf
Next

$avRetArray[0] = $iElements
Return $avRetArray
EndFunc

Func _FindInArray(ByRef $avArray, $StrToFind)
Local $iRetCount = 0
For $i = 1 To UBound($avArray)-1
If $avArray[$i] <> "" And $avArray[$i] = $StrToFind Then $iRetCount += 1
Next
If $iRetCount <> 0 Then Return $iRetCount
Return -1
EndFunc


Drsmog
если в блокноте, строке есть знак + тогда выполнить дествие
Примерно так:

$NotepadTitle = "[CLASS:Notepad]"

Run(@WindowsDir & "\Notepad.exe")
WinWait($NotepadTitle)

ControlSetText($NotepadTitle, "", "Edit1", "Просто текст с + ") ;Задаём текст с "+"

$EditText = ControlGetText($NotepadTitle, "", "Edit1")

If StringInStr($EditText, "+") Then
;Делаем наше действие ;)
MsgBox(0, "", "Это могло бы быть ваше действие ;)")
EndIf

;Просто закроем то что открыли
WinClose($NotepadTitle)
WinWaitClose($NotepadTitle, "", 1)
If WinActive("[CLASS:#32770]", "&") Then ControlClick("[CLASS:#32770]", "&", "Button2")

Drsmog
24-11-2007, 15:24
Огроменное спасибо !!!!!!!!!!!! :up :yahoo: :clapping:

fak1r
24-11-2007, 18:12
Такая вот у меня проблемка:
Есть один сайт на который нужно закачивать картинки, а что бы их закачать нада сначала пройти авторизацию вводом логина и пароля.
Так вот нельзя ли как нить сделать прогу на автоите для заливки картинок на этот сайт. очень нужно, а также необходим получать ссылки на залитые на сайт картинки.

PS вот сам сайт www.nn.ru
PSS вот тут http://www.nn.ru/services/personal-photo/ после регистрации будет галерея в котрую и нужно лить картинки.
Помогите пожалуйста!!!!
Заранее спасибо.

Drsmog
24-11-2007, 20:37
Нужна помощь !!!!!!!! Пажалуйста кто нибуть !!!!!!!!!!!! :help:

а если в блокноте, строке есть знак + тогда выполнить дествие, а если нет + тогда естественно другое дествие


я так примерно написал а почему то тока плюс проверяет

$NotepadTitle = "[CLASS:Notepad]"


WinWait($NotepadTitle)



$EditText = ControlGetText($NotepadTitle, "", "Edit1")

If StatusbarGetText ( $EditText,"+" ) Then
Send('{DOWN}')
;Делаем наше действие ;)
MsgBox(0, "", "ПЛЮС")
ElseIf StatusbarGetText ( $EditText, "-" ) Then
Send('{DOWN}')
;Делаем наше действие ;)
MsgBox(0, "", "МИНУС")


EndIf

Мне надо так
если +(тока в строке) тогда дествие
если -(тока в строке) тогда другое дествие
если ?(тока в строке) тогда другое дествие
ну и т.д

Creat0R
25-11-2007, 00:24
fak1r,
нельзя ли как нить сделать прогу на автоите для заливки картинок на этот сайт
Если помучаться, то наверняка можно, смотри в сторону TCP-функции, ну или через библиотеку IE.au3.

Drsmog,
StatusbarGetText
А при чём тут StatusBar? :unsure:

Мне надо так

$NotepadTitle = "[CLASS:Notepad]"

Run(@WindowsDir & "\Notepad.exe")
WinWait($NotepadTitle)

ControlSetText($NotepadTitle, "", "Edit1", "Просто текст с - ") ;Задаём текст с "-"

$EditText = ControlGetText($NotepadTitle, "", "Edit1")

Select
Case StringInStr($EditText, "+") And Not StringRegExp($EditText, "-|\?")
Action_Plus()
Case StringInStr($EditText, "-") And Not StringRegExp($EditText, "\+|\?")
Action_Minus()
Case StringInStr($EditText, "?") And Not StringRegExp($EditText, "\-|\+")
Action_Question()
EndSelect

;Просто закроем то что открыли
WinClose($NotepadTitle)
WinWaitClose($NotepadTitle, "", 1)
If WinActive("[CLASS:#32770]", "&") Then ControlClick("[CLASS:#32770]", "&", "Button2")

Func Action_Plus()
;Тут что-то делаем
MsgBox(0, "", "ПЛЮС")
EndFunc

Func Action_Minus()
;Тут делаем что-то другое
MsgBox(0, "", "МИНУС")
EndFunc

Func Action_Question()
;Тут делаем что-то другое
MsgBox(0, "", "ВОПРОС")
EndFunc

Я только не уверен, что значит “тока в строке”?

Drsmog
25-11-2007, 09:51
Этот скрипт проверяет всю страницу в блокноте на наличии знаков, а надо чтоб искал тока в строчке, допустим в блокноте
стоят знаки в столбик.
+
-
?
тогда этот скрипт несрабатывает.
Надо чтоб возле каждого символа писал слово
например
+ это плюс
- это минус
? а это вопрос

fak1r
25-11-2007, 11:36
fak1r,
Цитата:нельзя ли как нить сделать прогу на автоите для заливки картинок на этот сайт
Если помучаться, то наверняка можно, смотри в сторону TCP-функции, ну или через библиотеку IE.au3. »

То то и оно я не умею работать с TCP , а как спомощью IE.au3 авторизирваться на сайте тоже не знаю. :(

fak1r
25-11-2007, 11:51
да и я считаю что ТСР гораздо лучше будет работать чем ИЕ.ау3




© OSzone.net 2001-2012