将中文字符放入结构体中的心得
本帖最后由 tubaba 于 2016-10-19 16:29 编辑不知道大家是否翻看过坛子上的一篇贴子.
发现_GUICtrlListView_FindText搜索有个BUG,不支持中文完全匹配(已解决)
发现_GUICtrlListView_FindText搜索有个BUG,不支持中文完全匹配,问题续(已解决)
里面就涉及到将中文放入C/C++ 数据结构中的问题.其中Afan版主是这样解决的. Local $aSR = StringRegExp($sText, '[^\x00-\xff]', 3), $iL = UBound($aSR)
Local $iBuffer = StringLen($sText) + 1 + $iL
Local $tBuffer = DllStructCreate('char Text[' & $iBuffer & ']')
Local $pBuffer = DllStructGetPtr($tBuffer)
For $i = 0 To $iL - 2
$sText &= ' '
Next
DllStructSetData($tBuffer, 'Text', $sText)这果然是一个好办法.中文可以正确放入与取出了.但是最近我在写myscitejump的搜索中文功能时发现,如果编辑器内容是ansi编码,用这种方法没有问题.但是如果是utf8,那就不行了.在scintilla开发文档中,指出SCI_SEARCHINTARGET(int length, const char *text) → int
This searches for the first occurrence of a text string in the target defined by SCI_SETTARGETSTART and SCI_SETTARGETEND. The text string is not zero terminated; the size is set by length. The search is modified by the search flags set by SCI_SETSEARCHFLAGS. If the search succeeds, the target is set to the found text and the return value is the position of the start of the matching text. If the search fails, the result is -1.
必须将查询的关键字放入类型为char的结构体中.这就出现了一个问题.如何将"unicode字符放入char结构",这个问题困扰了我整一个星期.如何才能在scintilla中搜索中文.文档是ansi,用afan版主的方法是可行的.但是在utf8编码中,行不通了.猜想是中文ansi与unicode编码不一样造成的.在网上到处找资料.可惜现在研究AU3的人太少了.也没得到啥子结果.最后在翻看AU3帮助文档DllStructCreate中,突然灵光一闪.byte与char都是8位字符,区别在于一个是无符号,一个是ascII.
尝试创建byte结构,结果居然成功了!
下面将示例代码发出来,我想这一定能解决很多中文放入结构体的问题,将文本转换为二进制,至于长度不用特别计算.管它是中文还是英文,要关心的是ANSI编码还是UNICODE编码,然后直接用binarylen得到字节长度.
这样就不需要有几个汉字留几个空让其截断了,我认为应该比上面的办法更好一些{:face (356):}Func _Sci_FindInTarget($SerchText, $iStart, $iEnd) ;查找目标 ;消息原型.SCI_SEARCHINTARGET(int length, const char *text) → int
Local $sText = ''
Local $Codepage = _Sci_GetCodepage()
Switch $Codepage
Case 65001
$sText = StringToBinary($SerchText, 4) ;编码为UTF8
Case Else
$sText = StringToBinary($SerchText, 1) ;编码为ANSI
EndSwitch
Local $searchTextLen = BinaryLen($sText)
Local $tBuffer = DllStructCreate('byte buffer[' & $searchTextLen & ']') ;建立字节结构,unicode一个汉字占用3个字节,在这里使用byte,而不是char
Local $iBuffer = DllStructGetSize($tBuffer)
DllStructSetData($tBuffer, 'buffer', $sText) ;以字节的方式放入结构中,保证文本的完整性.否则可能在转换的过程中造成丢失
_Sci_SetTargetStart($iStart)
_Sci_SetTargetEnd($iEnd)
Local $tMemMap
Local $pMemory = _MemInit($__vSciTEAPI[$__hSciTEEdit], $iBuffer, $tMemMap) ;初始化内存分区 在目标进程划分大小为$iBuffer的内存
_MemWrite($tMemMap, $tBuffer) ;复制结构
Local $PosFind = _Sci_SearchInTarget($iBuffer, $pMemory)
If $PosFind = -1 Then
_Sci_SetTargetStart(0)
_Sci_SetTargetEnd($iStart - 1)
$PosFind = _Sci_SearchInTarget($iBuffer, $pMemory)
EndIf
Return $PosFind
EndFunc ;==>_Sci_FindInTarget同理,Afan版主的函数也可以这样修改Func __GUICtrlListView_FindItem($hWnd, $iStart, ByRef $tFindInfo, $sText = "")
Local $sBinText = StringToBinary($sText, 1)
Local $iBuffer = BinaryLen($sBinText)+1
Local $tBuffer = DllStructCreate("byte Text[" & $iBuffer & "]")
Local $pBuffer = DllStructGetPtr($tBuffer)
DllStructSetData($tBuffer, "Text", $sBinText)
Local $iRet
If IsHWnd($hWnd) Then
If _WinAPI_InProcess($hWnd, $__g_hLVLastWnd) Then
DllStructSetData($tFindInfo, "Text", $pBuffer)
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $tFindInfo, 0, "wparam", "struct*")
Else
Local $iFindInfo = DllStructGetSize($tFindInfo)
Local $tMemMap
Local $pMemory = _MemInit($hWnd, $iFindInfo + $iBuffer, $tMemMap)
Local $pText = $pMemory + $iFindInfo
DllStructSetData($tFindInfo, "Text", $pText)
_MemWrite($tMemMap, $tFindInfo, $pMemory, $iFindInfo)
_MemWrite($tMemMap, $tBuffer, $pText, $iBuffer)
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $pMemory, 0, "wparam", "ptr")
_MemFree($tMemMap)
EndIf
Else
DllStructSetData($tFindInfo, "Text", $pBuffer)
$iRet = GUICtrlSendMsg($hWnd, $LVM_FINDITEM, $iStart, DllStructGetPtr($tFindInfo))
EndIf
Return $iRet
EndFunc ;==>_GUICtrlListView_FindItem开贴留做备忘 afan原帖地址提供一下 哦,原来如此,昨晚手机看贴,没注意到 本帖最后由 131738 于 2016-10-20 11:01 编辑
不知道大家是否翻看过坛子上的一篇贴子.
里面就涉及到将中文放入C/C++ 数据结构中的问题.其中Afan版 ...
tubaba 发表于 2016-10-19 16:23 http://www.autoitx.com/images/common/back.gif
非常不错的研究结果, 如果我以后还会发布 AutoIt 安装包的话, 决定据此修改包含文件 GuiListView.au3 中的函数 _GUICtrlListView_FindItem() 一并发布................. 回复 1# tubaba
這篇我覺得是不是應該放到 中文資料區不然放在這久了 可能就消失了....
可能要請版主 移動一下吧
留個腳印 macgyver afan原帖地址提供一下
haijie1223 发表于 2016-10-19 23:36 http://www.autoitx.com/images/common/back.gif
应该就在 LZ 主贴给的链接贴中吧, 我也是现在才发现 _GUICtrlListView_FindItem() 确实不支持中文搜索的.............. 以前没有注意到这个函数,为什么搜索内容不能匹配第一个字符,就搜索不到呢? 回复 6# 131738
测试了一下还发现这个问题:
#include <GuiListView.au3>
GUICreate("ListView Find Text", 400, 300)
$hListView = GUICtrlCreateListView("", 2, 2, 394, 268)
GUISetState()
_GUICtrlListView_AddColumn($hListView, "Items", 100)
_GUICtrlListView_BeginUpdate($hListView)
For $iI = 4 To 49
_GUICtrlListView_AddItem($hListView, "en" & $iI)
Next
_GUICtrlListView_AddItem($hListView, "中文Target item")
For $iI = 51 To 100
_GUICtrlListView_AddItem($hListView, "Item " & $iI)
Next
_GUICtrlListView_AddItem($hListView, "end")
_GUICtrlListView_EndUpdate($hListView)
; 搜索目标项目
$iI = __GUICtrlListView_FindText($hListView, "文", -1, 1)
MsgBox(4160, "1", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "文", -1, 0)
MsgBox(4160, "2", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "中", -1, 1)
MsgBox(4160, "3", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "中", -1, 0)
MsgBox(4160, "4", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "Target", -1, 1)
MsgBox(4160, "5", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "Target", -1, 0)
MsgBox(4160, "6", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
Do
Until GUIGetMsg() = -3
GUIDelete()
Func __GUICtrlListView_FindText($hWnd, $sText, $iStart = -1, $fPartialOK = True, $fWrapOK = True)
Local $tFindInfo = DllStructCreate($tagLVFINDINFO)
Local $iFlags = $LVFI_STRING
;~ Local $iFlags = $LVFI_SUBSTRING
If $fPartialOK Then $iFlags = BitOR($iFlags, $LVFI_SUBSTRING)
If $fWrapOK Then $iFlags = BitOR($iFlags, $LVFI_WRAP)
DllStructSetData($tFindInfo, "Flags", $iFlags)
Return __GUICtrlListView_FindItem($hWnd, $iStart, $tFindInfo, $sText)
EndFunc ;==>__GUICtrlListView_FindText
Func __GUICtrlListView_FindItem($hWnd, $iStart, ByRef $tFindInfo, $sText = "")
Local $sBinText = StringToBinary($sText, 1)
Local $iBuffer = BinaryLen($sBinText) + 1
Local $tBuffer = DllStructCreate("byte Text[" & $iBuffer & "]")
Local $pBuffer = DllStructGetPtr($tBuffer)
DllStructSetData($tBuffer, "Text", $sBinText)
Local $iRet
If IsHWnd($hWnd) Then
If _WinAPI_InProcess($hWnd, $__g_hLVLastWnd) Then
DllStructSetData($tFindInfo, "Text", $pBuffer)
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $tFindInfo, 0, "wparam", "struct*")
Else
Local $iFindInfo = DllStructGetSize($tFindInfo)
Local $tMemMap
Local $pMemory = _MemInit($hWnd, $iFindInfo + $iBuffer, $tMemMap)
Local $pText = $pMemory + $iFindInfo
DllStructSetData($tFindInfo, "Text", $pText)
_MemWrite($tMemMap, $tFindInfo, $pMemory, $iFindInfo)
_MemWrite($tMemMap, $tBuffer, $pText, $iBuffer)
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $pMemory, 0, "wparam", "ptr")
_MemFree($tMemMap)
EndIf
Else
DllStructSetData($tFindInfo, "Text", $pBuffer)
$iRet = GUICtrlSendMsg($hWnd, $LVM_FINDITEM, $iStart, DllStructGetPtr($tFindInfo))
EndIf
Return $iRet
EndFunc ;==>__GUICtrlListView_FindItem
Func __GUICtrlListView_FindItemAfan($hWnd, $iStart, ByRef $tFindInfo, $sText = '')
Local $aSR = StringRegExp($sText, '[^\x00-\xff]', 3), $iL = UBound($aSR)
Local $iBuffer = StringLen($sText) + 1 + $iL
Local $tBuffer = DllStructCreate('char Text[' & $iBuffer & ']')
Local $pBuffer = DllStructGetPtr($tBuffer)
For $i = 0 To $iL - 2
$sText &= ' '
Next
DllStructSetData($tBuffer, 'Text', $sText)
Local $iRet
If IsHWnd($hWnd) Then
If _WinAPI_InProcess($hWnd, $__g_hLVLastWnd) Then
DllStructSetData($tFindInfo, 'Text', $pBuffer)
ConsoleWrite('222')
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $tFindInfo, 0, 'wparam', 'struct*')
Else
Local $iFindInfo = DllStructGetSize($tFindInfo)
Local $tMemMap
Local $pMemory = _MemInit($hWnd, $iFindInfo + $iBuffer, $tMemMap)
Local $pText = $pMemory + $iFindInfo
DllStructSetData($tFindInfo, 'Text', $pText)
_MemWrite($tMemMap, $tFindInfo, $pMemory, $iFindInfo)
_MemWrite($tMemMap, $tBuffer, $pText, $iBuffer)
ConsoleWrite('0000')
$iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $pMemory, 0, 'wparam', 'ptr')
_MemFree($tMemMap)
EndIf
Else
DllStructSetData($tFindInfo, 'Text', $pBuffer)
ConsoleWrite('111111111')
$iRet = GUICtrlSendMsg($hWnd, $LVM_FINDITEM, $iStart, DllStructGetPtr($tFindInfo))
EndIf
Return $iRet
EndFunc ;==>__GUICtrlListView_FindItemAfan
虽然看不懂,还是顶一下.....{:face (332):} 本帖最后由 131738 于 2016-10-20 12:37 编辑
回复131738
测试了一下还发现这个问题:
haijie1223 发表于 2016-10-20 11:17 http://www.autoitx.com/images/common/back.gif
单汉字搜索失败, 返回 -1, 但单字母却可以, 这个就不懂了.......
afan 应该可以解决吧......... 本帖最后由 tubaba 于 2016-10-20 12:48 编辑
回复 8# haijie1223
刚才看了下函数文档,$bPartialOK [可选] 如为 True, 只要项目文本开头匹配 $sText 的开头, 则搜索成立 ,所以理解为分二种情况,一种是开头匹配,一种是完整匹配,所以想匹配中间的没门$iI = __GUICtrlListView_FindText($hListView, "文", -1, 1) ;$bPartialOK =true ,第一个字不匹配,搜索不成立
MsgBox(4160, "1", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "文", -1, 0) ;$bPartialOK =false,整个项目文本不匹配,搜索不成立
MsgBox(4160, "2", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
;~ $iI = __GUICtrlListView_FindText($hListView, "中", -1, 1) ;$bPartialOK =true ,第一个字匹配,搜索成立
;~ MsgBox(4160, "3", "Target Item Index: " & $iI)
;~ If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "中", -1, 0) ;$bPartialOK=false,整个项目文本不匹配,搜索不成立
MsgBox(4160, "4", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)f
$iI = __GUICtrlListView_FindText($hListView, "Target", -1, 1) ;$bPartialOK =true ,第一个字不匹配,搜索不成立
MsgBox(4160, "5", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "Target", -1, 0) ;$bPartialOK =false ,整个字不匹配,搜索不成立
MsgBox(4160, "6", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)3643]10# 131738
请教怎么个语法着色? 另外,myscitejump已经支持中文搜索.并将注释,控件命令搜索加入树视图.等下放出exe,请你测试 回复 11# tubaba
"请教怎么个语法着色?" 抱歉! 我不懂......... 回复 12# 131738
sorry,没写清楚,就是haijie1223贴子里的代码引用部分,是经过语法着色的,而我发出来的是清一色的.怎么个弄法 回复 11# tubaba
"请教怎么个语法着色?" 抱歉! 我不懂.........
" $iI = __GUICtrlListView_FindText($hListView, "中", -1, 1) ;$bPartialOK =true ,第一个字匹配,搜索成立"但返回索引似乎不对.......... 回复 14# 131738
因为For $iI = 4 To 49 :),他不是从一开始的....
另外你可以试下 $iI = __GUICtrlListView_FindText($hListView, "a", -1, 1) ;$bPartialOK =true ,第一个字不匹配,搜索不成立
MsgBox(4160, "7", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "I", -1, 1) ;$bPartialOK =true ,第一个字匹配,搜索成立
MsgBox(4160, "8", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)
$iI = __GUICtrlListView_FindText($hListView, "I", -1, 0) ;$bPartialOK =false ,整个文本不匹配,搜索不成立
MsgBox(4160, "9", "Target Item Index: " & $iI)
If $iI <> -1 Then _GUICtrlListView_EnsureVisible($hListView, $iI)这个函数应该是没错的
页:
[1]
2