Excel正则匹配提取、替换、定位工具
;------------------------------------------------
;名字:Excel正则匹配提取、替换、定位工具
;功能:正则匹配提取、替换、定位
;作者:qq576642385 微信15520035235
;时间:2018-8-26
;------------------------------------------------
#SingleInstance force
#NoEnv
SetWorkingDir %A_ScriptDir%
Process, Priority,, High
SetControlDelay -1
SendMode Input
#IfWinActive,ahk_exe EXCEL.EXE
#q:: ;热键
ExRegExcel :=Excel_Get()
if !IsObject(ExRegExcel)
{
MsgBox,无活动的Excel对象!
return
}
正则匹配替换定位帮助=
(
-------------------------------------------------
Name :Excel正则匹配、替换、定位工具
QQ :576642385(1799)
Weixin :15520035235
Time : 2018-8-26
-------------------------------------------------
帮助相关说明:
1、此工具仅限于Excel中使用
2、匹配提取、替换都是在原数据单元格执行,注意备份
3、不区分大小写需设置:i) 选项
4、需要把源字符串按多行匹配,需设置:m)(*ANYCRLF)
5、匹配或替换的最大次数:-1 表示全部
6、撤销一次:只能尝试是否能撤销1次,最多1次
7、有公式的单元格,将以结果作为匹配的源数据,如:=10+10 结果为20,将以20的实际形式进行匹配
8、所有操作均不涉及单元格格式的改变
9、正则定位中的非模式:abc定位含有abc的单元格,启用非模式表示定位到不含abc的单元格
10、单元格为数值格式时,数字后面会匹配成功1个空格,不知道为何
11、合并单元格仅第一格存在数据,其他为空白单元格,定位时会匹配空白单元格
)
注意说明=
(
--------------数据无价---------------
1. 执行后不能撤销,请保存好原数据;
2. 正则匹配模式:默认只匹配1次;
3. 正则替换模式:默认全部替换;
--------------慎重使用---------------
)
常用正则代码命令=
(
匹配数字
匹配字母
匹配中文
匹配空白单元格
匹配首尾空格
匹配所有空格
首尾插入文字
分段提取内容
)
参考正则代码=
(
1、非空白单元格-1799:.+
2、非负整数-1799:^\d+$
3、正整数-1799:^[1-9]{1}[0-9]*$
4、非正整数:^((-\d+)|(0+))$
5、负整数:^-[0-9]*[1-9][0-9]*$
6、整数:^-?\d+$
7、手机号码:^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$
8、电话号码:^((\(\d{2,3}\))|(\d{3}\-))?(\(0\d{2,3}\)|0\d{2,3}-)?[1-9] \d{6,7}(\-\d{1,4})?$
9、提取《》中的内容-1799:(?<=《).*?(?=》)
10、提取【】中的内容-1799:(?<=【).*?(?=】)
11、提取〖〗中的内容-1799:(?<=〖).*?(?=〗)
12、提取[]中的内容-1799:(?<=\[).*?(?=\])
13、提取指定内容之前的内容-1799:^.*?(?=xxx)
)
ExRegExMode :="匹配模式"
ExRegExHighMode :=0
ExRegHelp :=0
ExAddEx :=0
WinGet, ExRegExHwnd,ID,A
Gui,Destroy
Gui Add, GroupBox, x5 y5 w125 h78, 模式设置
Gui Add, Radio, x15 y20 w65 h20 gEx切换模式1 +Checked, 正则匹配
Gui Add, Radio, x15 y40 w65 h20 gEx切换模式2, 正则替换
Gui Add, Radio, x15 y60 w65 h20 gEx切换模式3 , 正则定位
Gui Add, Checkbox, x88 y61 w30 h20 cred vExRegExDWF, 非
Gui Add, GroupBox, x5 y85 w125 h275, 常用正则代码
Gui,Font,s9,Microsoft YaHei
Gui Add, ListView, x10 y103 w114 h250 gExRegExList AltSubmit +Grid +NoSortHdr -Multi -Hdr, ListViewtt
Gui,Font
Gui Add, GroupBox, x135 y5 w255 h355, 功能执行
Gui Add, Text, x143 y23 w120 h23 gExAddEx +0x200, 正则表达式:
Gui Add, Edit, x142 y48 w240 cblue r3 vEx正则表达式 -VScroll
Gui Add, Text, x143 y100 w240 h23 vExReTh +0x200, 如需提取子模式值,请输入子模式的序列号:
Gui Add, Edit, x142 y125 w240 cred r3 vEx正则替换内容 -VScroll
Gui,Font,s9,Microsoft YaHei
Gui Add, Text, x143 y175 cred r3, %注意说明% ;注意事项
Gui,Font
Gui Add, Checkbox, x142 y255 w65 h20 vExRegExSetting gExRegExSetting, 高级设置
Gui Add, Text, x157 y275 w140 h20 +0x200, 最大匹配或者替换次数:
Gui Add, Text, x157 y295 w140 h20 +0x200, 匹配模式匹配项连接符:
Gui,Font,s8 Bold
Gui Add, Edit, x284 y277 w65 h17 vExRegExMaxC -VScroll
Gui Add, Edit, x284 y297 w65 h17 vExRegExLinkF -VScroll ;正则匹配多次时,各匹配间的连接符号
Gui,Font
Gui Add, Button, x142 y325 w110 h25 gExRegExRevoke, 撤销一次 ;尝试撤销一次,不能确保成功
Gui Add, Button, x267 y325 w110 h25 vExRegExAc gEx执行, 匹配提取
Gui Add, Text, x0 y360 w400 h2 0x10 ;单线
Gui Add, Text, x5 y362 w40 h15 gExRegHelp +0x200, 状态栏:
Gui Add, Text, x47 y362 w284 h15 cred vExStateBar +0x200,欢迎使用正则匹配! ;状态栏提示
Gui Font, Bold
Gui Add, Text, x340 y362 w120 h15 +0x200 vExCurrentMode gExClearAll cblue, 匹配模式
Gui Font
Gui Add,Edit,x400 y11 w320 h365 vExRegCKZZ
Loop, parse, 常用正则代码命令, `n, `r
LV_Add(,A_LoopField)
Gui +AlwaysOnTop -MinimizeBox -MaximizeBox +ToolWindow
GuiControl,Disabled,ExRegExMaxC
GuiControl,Disabled,ExRegExLinkF
GuiControl,Disabled,ExRegExDWF
Gui Show, w400 h380, Excel正则匹配、替换、定位
Return
ExRegHelp:
if ExRegHelp=0
{
GuiControl,,ExRegCKZZ,%正则匹配替换定位帮助%
WinMove,Excel正则匹配、替换、定位,,,,728
ExRegHelp=1
ExAddEx=0
}
else
{
WinMove,Excel正则匹配、替换、定位,,,,400
ExRegHelp=0
}
return
ExAddEx:
if ExAddEx=0
{
GuiControl,,ExRegCKZZ,%参考正则代码%
WinMove,Excel正则匹配、替换、定位,,,,728
ExAddEx=1
ExRegHelp=0
}
else
{
WinMove,Excel正则匹配、替换、定位,,,,400
ExAddEx=0
}
return
Ex切换模式1:
ExRegExMode :="匹配模式"
GuiControl,Enable,Ex正则替换内容
GuiControl,Enabled,ExRegExSetting
GuiControl,Disabled,ExRegExDWF
if ExRegExHighMode
{
GuiControl,Enabled,ExRegExMaxC
GuiControl,Enabled,ExRegExLinkF
}
GuiControl,,ExReTh,如需提取子模式值,请输入子模式的序列号:
GuiControl,,ExRegExAc,匹配提取
GuiControl,,ExStateBar,欢迎使用正则匹配!
GuiControl,,ExCurrentMode,%ExRegExMode%
return
Ex切换模式2:
ExRegExMode :="替换模式"
GuiControl,Enable,Ex正则替换内容
GuiControl,Enabled,ExRegExSetting
GuiControl,Disabled,ExRegExDWF
if ExRegExHighMode
{
GuiControl,Enabled,ExRegExMaxC
GuiControl,Disabled,ExRegExLinkF
}
GuiControl,,ExReTh,匹配内容替换为:
GuiControl,,ExRegExAc,正则替换
GuiControl,,ExStateBar,欢迎使用正则替换!
GuiControl,,ExCurrentMode,%ExRegExMode%
return
Ex切换模式3:
ExRegExMode :="定位模式"
GuiControl,Enabled,ExRegExDWF
GuiControl,Disable,Ex正则替换内容
GuiControl,Disable,ExRegExSetting
GuiControl,Disabled,ExRegExMaxC
GuiControl,Disabled,ExRegExLinkF
GuiControl,,ExRegExAc,正则定位
GuiControl,,ExStateBar,欢迎使用正则定位!
GuiControl,,ExCurrentMode,%ExRegExMode%
return
匹配数字:
GuiControl,,Ex正则表达式,\d
GuiControl,,ExStateBar,匹配0-9数字但不匹配小数点及正负符号!
GuiControl,,Ex正则替换内容
return
匹配字母:
GuiControl,,Ex正则表达式,[a-zA-Z]
GuiControl,,ExStateBar,匹配所有字母小写及大写!
GuiControl,,Ex正则替换内容
return
匹配中文:
GuiControl,,Ex正则表达式,[\x{4e00}-\x{9fa5}]
GuiControl,,ExStateBar,匹配所有中文!
GuiControl,,Ex正则替换内容
return
匹配空白单元格:
GuiControl,,Ex正则表达式,^$
GuiControl,,ExStateBar,匹配空白单元格!
GuiControl,,Ex正则替换内容
return
匹配首尾空格:
GuiControl,,Ex正则表达式,(^ +)|(%A_Space%+$)
GuiControl,,ExStateBar,匹配首尾单个或多个空格!
GuiControl,,Ex正则替换内容
return
匹配所有空格:
GuiControl,,Ex正则表达式,%A_Space%
GuiControl,,ExStateBar,匹配所有空格!
GuiControl,,Ex正则替换内容
return
首尾插入文字:
GuiControl,,Ex正则表达式,.+
GuiControl,,ExStateBar,请在“$0”前或后输入需要插入的内容。
GuiControl,,Ex正则替换内容,$0
return
分段提取内容:
GuiControl,,Ex正则表达式,^(.{3}).*
GuiControl,,ExStateBar,例取前三个字符:^(.{3}).* 后3个字符:.*(.{3})$
GuiControl,,Ex正则替换内容,$1
return
ExClearAll:
GuiControl,,Ex正则表达式
GuiControl,,Ex正则替换内容
GuiControl,,ExRegExMaxC
GuiControl,,ExStateBar,清空表达式及替换内容,完成!
return
ExRegExSetting: ;高级设置
if !ExRegExHighMode
{
if ExRegExMode=匹配模式
GuiControl,Enabled,ExRegExLinkF
else
GuiControl,Disabled,ExRegExLinkF
GuiControl,Enabled,ExRegExMaxC
ExRegExHighMode :=1
}
else
{
GuiControl,Disabled,ExRegExMaxC
GuiControl,Disabled,ExRegExLinkF
ExRegExHighMode :=0
}
return
ExRegExList:
if A_GuiEvent = Normal ; 单击
{
ExRegExRowNumber = 0
Loop
{
ExRegExRowNumber := LV_GetNext(ExRegExRowNumber)
if not ExRegExRowNumber
break
LV_GetText(ExRegExListItem, ExRegExRowNumber)
if ExRegExListItem
gosub,%ExRegExListItem%
return
}
}
return
;执行功能
Ex执行:
if RegExMatch(ExRegExcel.selection.address,"(?<![A-Z0-9])\$[A-Z0-9]+:\$[A-Z0-9]+")
{
ExLastCellAddress :=xlFindLastCell(ExRegExcel)
if !ExLastCellAddress
return
ExRegExNewSelection :=ExRegExcel.Intersect(ExRegExcel.selection,ExRegExcel.Range("$A$1:"ExLastCellAddress))
}
else
{
ExRegExNewSelection :=ExRegExcel.Intersect(ExRegExcel.selection,ExRegExcel.selection)
}
EXxrquzj :=ExRegExNewSelection.Count
Gui,Submit,NoHide
;第2步:开始模式判断
;匹配模式
if ExRegExMode=匹配模式 ;如果是匹配模式
{
if (Ex正则表达式="") ;如果正则表达式为空白,将结束
{
Gui +OwnDialogs
MsgBox,正则表达式为空白!
return
}
if !(Ex正则替换内容 ~= "(^$)|(^[1-9]{1}[0-9]*$)") ;输入子模式序列号格式判断,可为正整数或为空白
{
Gui +OwnDialogs
MsgBox,子模式序列号错误!
return
}
if !ExRegExHighMode ;未开启高级模式
ExRegMatchC :=1 ;需匹配次数为1,不再重复匹配
else ;开启了高级模式
{
if ExRegExMaxC ~= "(^[1-9]{1}[0-9]*$)|(-1)" ;输入如果为正整数或为-1
ExRegMatchC :=ExRegExMaxC
else
{
Gui +OwnDialogs
MsgBox,输入最大匹配次数不正确!
return
}
}
Exzsjidj=0
Gui +OwnDialogs
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
Progress, show
gosub,ExRegExCopyData ;开始备份数据,以便可以尝试撤销一次
For ExRegExCell,ExRegExRn In ExRegExNewSelection
{
Exzsjidj++
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
ExMatchAllValue :=""
ExMatchArray :=RegExMatchAll(ExRegExCell.text, Ex正则表达式,ExRegMatchC,Ex正则替换内容)
if ExMatchArray
{
for xuhk1,valuel in ExMatchArray
ExMatchAllValue .=ExMatchAllValue ? ExRegExLinkF . valuel : valuel
}
else
ExMatchAllValue :=""
ExRegExCell.Value :=ExMatchAllValue
}
GuiControl,,ExStateBar,匹配提取完成!
Progress, off
Sleep,50
WinActivate,ahk_id %ExRegExHwnd%
SetTimer,ExRegExToolTip3,-1
return
}
;替换模式
If ExRegExMode=替换模式
{
if (Ex正则表达式="") ;如果正则表达式为空白,将结束
{
Gui +OwnDialogs
MsgBox,正则表达式为空白!
return
}
if !ExRegExHighMode ;未开启高级模式
ExRegExLimit :=-1
else ;已开启高级模式
{
if ExRegExMaxC ~= "(^[1-9]{1}[0-9]*$)|(-1)" ;输入如果为正整数或为-1
ExRegExLimit :=ExRegExMaxC
else
{
Gui +OwnDialogs
MsgBox,输入次数不正确!
return
}
}
Exzsjidj=0
Gui +OwnDialogs
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
Progress, show
gosub,ExRegExCopyData ;开始备份数据,以便可以尝试撤销一次
For ExRegExCell,ExRegExRn In ExRegExNewSelection
{
Exzsjidj++
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
ExRegExCell.Value :=RegExReplace(ExRegExCell.text,Ex正则表达式,Ex正则替换内容,,ExRegExLimit)
}
GuiControl,,ExStateBar,替换完成!
Progress, off
Sleep,50
WinActivate,ahk_id %ExRegExHwnd%
SetTimer,ExRegExToolTip1,-1
return
}
Else ;定位模式 ,定位模式不需要备份数据
{
if (Ex正则表达式="") ;如果正则表达式为空白,将结束
{
Gui +OwnDialogs
MsgBox,正则表达式为空白!
return
}
Exzsjidj=0
Gui +OwnDialogs
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
Progress, show
ExRegExD :=ComObjCreate("Scripting.Dictionary")
For ExRegExCell,ExRegExRn In ExRegExNewSelection
{
If !ExRegExD.exists(ExRegExCell.Address)
ExRegExD.Add(ExRegExCell.Address,ExRegExCell.Text)
else
continue
}
ExRegExAddress :=""
if !ExRegExDWF ;定位非模式判断
{
for ExRegExKey in ExRegExD
{
Exzsjidj++
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
If RegExMatch(ExRegExD.item(ExRegExKey),Ex正则表达式)
ExRegExAddress .=ExRegExAddress? ","ExRegExKey : ExRegExKey
}
}
else
{
for ExRegExKey in ExRegExD
{
Exzsjidj++
Progress, % Exzsjidj/Exxrquzj*100 ,执行进度 , 勿动选区, 请稍等。。。
If RegExMatch(ExRegExD.item(ExRegExKey),Ex正则表达式)=0
ExRegExAddress .=ExRegExAddress? ","ExRegExKey : ExRegExKey
}
}
ExRegExAddress :=StrReplace(ExRegExAddress, "$") ;删除所有地址的$符号
If ExRegExAddress
{
if StrLen(ExRegExAddress)<=255
{
ExRegExcel.Intersect(ExRegExcel.Range(ExRegExAddress),ExRegExcel.Range(ExRegExAddress)).Select
Progress, off
;;ExRegExcel.Range(ExRegExAddress).Select
Sleep,50
WinActivate,ahk_id %ExRegExHwnd%
GuiControl,,ExStateBar,定位完成!
SetTimer,ExRegExToolTip2,-1
return
}
else
{
ExRegExLen :=0
ExRegExNum :=0
loop
{
if StrLen(ExRegExAddress)>255
{
ExRegExNum++
RegExMatch(ExRegExAddress,"O).{2,255}(?=,)",ExRegExAddress%A_Index%)
ExRegExLen := ExRegExAddress%A_Index%.Len + 2
ExRegExAddress :=SubStr(ExRegExAddress,ExRegExLen)
continue
}
ExRegExNum++
RegExMatch(ExRegExAddress,"O).{2,255}",ExRegExAddress%A_Index%)
break
}
ExRegExzAdr :=ExRegExcel.Range(ExRegExAddress1.Value)
Loop, % ExRegExNum - 1
{
ExRegExIndex :=A_Index + 1
ExRegExzAdr :=ExRegExcel.Union(ExRegExzAdr,ExRegExcel.Range(ExRegExAddress%ExRegExIndex%.Value))
}
ExRegExcel.Intersect(ExRegExzAdr,ExRegExzAdr).Select
Progress, off
;ExRegExzAdr.Select
Sleep,50
WinActivate,ahk_id %ExRegExHwnd%
GuiControl,,ExStateBar,定位完成!
SetTimer,ExRegExToolTip2,-1
return
}
}
Progress, off
GuiControl,,ExStateBar,未找到存在条件的单元格!
}
return
GuiEscape:
GuiClose:
ExRegExcel :=""
Excel :=""
ExNavExcel :=""
oexcel :=""
XlieExcel :=""
Gui,Destroy
return
ExRegExToolTip1:
ToolTip,正则替换完成
Sleep,400
ToolTip
return
ExRegExToolTip2:
ToolTip,正则定位完成
Sleep,400
ToolTip
return
ExRegExToolTip3:
ToolTip,正则匹配提取完成
Sleep,400
ToolTip
return
;备份数据
ExRegExCopyData:
ExCopyDataD :=ComObjCreate("Scripting.Dictionary")
For ExCopyCell,ExCopyRn In ExRegExNewSelection
{
If !ExCopyDataD.exists(ExCopyCell.Address)
ExCopyDataD.Add(ExCopyCell.Address,ExCopyCell.Formula)
else
{
ExCopyDataD :=""
Gui +OwnDialogs
MsgBox,存在重复选区,请重新选择!
return
}
}
return
;尝试撤销一次,只能一次
ExRegExRevoke:
if !ExCopyDataD
{
GuiControl,,ExStateBar,已经撤销过1次,或无可撤销的数据!
Gui +OwnDialogs
MsgBox,撤销失败!
return
}
Tcas :=ExCopyDataD.Count
Exzsjidj=0
Gui +OwnDialogs
Progress, % Exzsjidj/Tcas*100 ,执行进度 , 勿动选区, 请稍等。。。
Progress, show
for ExRevokeCellAddr in ExCopyDataD
{
Exzsjidj++
ExRegExcel.Range(ExRevokeCellAddr) :=ExCopyDataD.item(ExRevokeCellAddr)
Progress, % Exzsjidj/Tcas*100 ,执行进度 , 勿动选区, 请稍等。。。
}
ExCopyDataD :=""
Progress, Off
Gui +OwnDialogs
GuiControl,,ExStateBar,撤销数据成功!
MsgBox,撤销成功!
return
RegExMatchAll(str, re, max_num:=1, re_num="") {
arr:=[], pos:=1, r:="",nc:=1
if max_num <>-1
{
While (pos:=RegExMatch(str, re, r, pos+StrLen(r))) and (nc<=max_num)
{
arr.Push( r%re_num% )
nc++
}
return, arr.MaxIndex() ? arr : ""
}
While (pos:=RegExMatch(str, re, r, pos+StrLen(r)))
arr.Push( r%re_num% )
return, arr.MaxIndex() ? arr : ""
}
xlFindLastCell(objExcel) {
static xlByRows := 1
, xlByColumns := 2
, xlPrevious := 2
lastRow := objExcel.ActiveSheet.Cells.Find("*", , , , xlByRows , xlPrevious).Row
lastCol := objExcel.ActiveSheet.Cells.Find("*", , , , xlByColumns, xlPrevious).Column
if lastRow
return objExcel.Cells(lastRow,lastCol).Address
return
}
; Excel_Get by jethrow (modified)
; Forum: https://autohotkey.com/boards/viewtopic.php?f=6&t=31840
; Github: https://github.com/ahkon/MS-Office-COM-Basics/blob/master/Examples/Excel/Excel_Get.ahk
Excel_Get(WinTitle:="ahk_class XLMAIN", Excel7#:=1) {
static h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
WinGetClass, WinClass, %WinTitle%
if !(WinClass == "XLMAIN")
return "Window class mismatch."
ControlGet, hwnd, hwnd,, Excel7%Excel7#%, %WinTitle%
if (ErrorLevel)
return "Error accessing the control hWnd."
VarSetCapacity(IID_IDispatch, 16)
NumPut(0x46000000000000C0, NumPut(0x0000000000020400, IID_IDispatch, "Int64"), "Int64")
if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", -16, "Ptr", &IID_IDispatch, "Ptr*", pacc) != 0
return "Error calling AccessibleObjectFromWindow."
window := ComObject(9, pacc, 1)
if ComObjType(window) != 9
return "Error wrapping the window object."
Loop
try return window.Application
catch e
if SubStr(e.message, 1, 10) = "0x80010001"
ControlSend, Excel7%Excel7#%, {Esc}, %WinTitle%
else
return "Error accessing the application object."
}
;---------Excel正则匹配提取、替换、定位工具------End