[AHK-lib分享] 一键从字符串中提取含有某关键字(字符串)
2018-11-21 本文已影响5人
d61f25068828
AHK-Lib002
使用场景
经常随手写一些灵感,但是分类整理的时候会很麻烦,因为太零碎了,所以需要逐行阅读,并且剪切复制,如果能够让程序自动的提取带有某字符串的行,那会省很多事情。比如我记录了很多关于AHK的灵感,他们很多都带有“AHK”这个字符串,这个时候我就可以用这个函数一键提取那些字符串。
优缺点以及可能的改进
已经满足了我的需求,如果再改进的话,那很可能是支持带格式发出,现在当然支持纯文本。但是我好像一点思路也没有,已经尝试将ClipBoard保存到本地,结果打开之后全是乱码,切换了一下,也没找到正确的编码。如果谁知道带格式筛选处理的方法,麻烦您告诉我一下,一起让这个lib变得更好。
老规矩,直接看实战 O(∩_∩)O~
实战案例-1
案例-1设计目标
一键分离带有某字符串的行。
选中文本并按下Shift+Alt+R,弹出一个输入框,让用户输入关键词,然后提取文本中的所有关键词,有关键词的行放入剪贴板,没有的重新放回文本编辑器中(覆盖原来的文本)。
案例-1动图效果展示
AHK-Lib002-一键从字符串中提取含有某关键字(字符串)的行-KeysExtract.gif.gif案例-1代码
+!r::
;# 拷贝并且备份
needline:=SuperCopy(20)
;## 备份
needPath:="D:\程序与机动文档\重要文档\行动管理文档\A收集箱(打断&Exception)整理\收集箱KeysExtract备份(按日期)\收集箱KeysExtract备份_" ReturnDate("nyruf") ".txt"
;# 提示用户输入关键词
InputBox,needkey,一键筛选行,请输入要查找的关键词(支持通过‘|’实现多关键词筛选)`r`n筛选之前会先备份 保证数据安全`r`n可以通过添加"[Mode2]"或"[Mode0]"来更改替换模式为2(只留下匹配的)或0(不修改文本)`r`n`:`:`/mz::[Mode0] (z代表Zero) `:`:/mt`:`:[Mode2] (t代表Two)
;## 如果发现用户取消了,那么什么也不做
if (ErrorLevel=1){
TrayTip,,已取消
return
}
;# 默认的是模式1,如果在needkey中加入特征字串可以修改
ModifyMode=1
if checkString(needkey,"[Mode0]"){
;# 把关键词特征字串给删除掉
needkey := StrReplace(needkey,"[Mode0]")
needkey := StrReplace(needkey,"[Mode0] ")
;# 更改KeysExtract模式为0
ModifyMode=0
}
else if checkString(needkey,"[Mode2]"){
;# 把关键词特征字串给删除掉
needkey := StrReplace(needkey,"[Mode2]")
needkey := StrReplace(needkey,"[Mode2] ")
;# 更改KeysExtract模式为1
ModifyMode=2
}
TxtBackUp(needline,needPath)
;# 留下的是不匹配的,匹配的放在剪切板上面
MsgString:=KeysExtract(needline,needkey,false,ModifyMode,true)[1]
Sleep 500
;~ MsgBox,% MsgString
return
lib代码
/*◆
# Library 库名 : KeysExtract.ahk
# Specification(Default ParaMeters) 功能介绍(默认参数下) :
一键从字符串中提取含有某关键字(字符串)的行
# ParaMetersList 参数列表 :
Str是输入的字符串
TheKeys是需要去检查匹配的"关键词",可以使用‘|’设立多个关键词(是‘或’的关系)
EnablereturnArray 打开之后,不返回合并好的String,而是返回String二维数组,关闭则返回String一维数组。[1]是匹配的,[2]是不匹配的。
ModifyMode是修改模式,当使用复制调用该函数的时候,可以直接修改对应文本。0代表关闭模式,1只留下不匹配的UnMatchedString(最常用),2,只留下匹配的,MatchedString。改参数只有EnablereturnArray打开时才有效果。
EnableWriteClip是否放到剪贴板上,这个必须在ModifyMode开启的情况下才有用,开启之后部分内容替换原来选中的内容,剩下的内容放到剪切板上。
EnableTrayTip,这个不用多说,很简单,就是"是否开启托盘通知",默认是开的
# Author & AHK Version AHK版本&作者 :
AHKv1.1.30 & 心如止水(QQ:2531574300)
# Copyright 版权声明 :
如果该文侵犯了您的权利,请联系我解决。
欢迎转载/改变,如果您觉得我的分享有帮助,希望您能在作品上标注原文地址。
# Library Version 库版本 :
v1.0 : KeysExtract.ahk 的第一个版本上线了 O(∩_∩)O~
# 依赖库 :
[请填写依赖库名]
# 常见问题 :
有没有实战案例?
不一定每个都有,如果有就在这里 https://pan.baidu.com/s/1EHeg3MhQm5MRPgIR-l928Q
# Quality Test 出厂品控检测 :
√
*/
KeysExtract(Str,TheKeys,EnableReturnArray:=false,ModifyMode:=false,EnableWriteClip:=false,EnableTrayTip:=true){
;# 声明局部变量
local MatchedArray,ScrArray,SuBkey,ScrArray,ReturnString,UnMatchedNumber,MatchedNumber
MatchedNumber:=0
UnMatchedNumber:=0
;# 如果修改模式打开着,并且返回数组模式也打开着,那么就报错
if !(ModifyMode!=false) AND (EnableReturnArray)
throw ("ModifyMode只在EnableReturnrray关闭时才生效")
;# 创建数组后, 初始为空
MatchedArray := []
UnMatchedArray := []
;# 去除空行
Str:=RemoveAllBlankLines(Str)
;# 以行为单位,分割为数组(源数组)
ScrArray := StrSplit(Str,"`r`n")
;# 检测
loop % ScrArray.MaxIndex()
{
;# 拿出每个行的字符串来
substring := ScrArray[a_index]
;# 检测看看包含不包含指定词汇
SuBkey:=checkString(substring,TheKeys)
;# 如果包含那就加进MatchedArray,否则加进UnMatchedArray
;## 进行统计
if (SuBkey){
MatchedArray.Push(substring)
MatchedNumber++
}
else{
UnMatchedArray.Push(substring)
UnMatchedNumber++
}
}
;# 出了检测循环之后,用一下tarytip提示一下数量
if (EnableTrayTip)
TrayTip,关键词提取匹配数量,%MatchedNumber%行成功匹配`r`n%UnMatchedNumber%行未能匹配
;# 如果要求返回数组,那就直接返回
if (EnableReturnArray){
return [MatchedArray,UnMatchedArray]
}
;# 如果不要求,那就重新合成行,并且返回一个数组,分别带有匹配的行组成的String,和不匹配的
else{
;# 初始化一下
MatchedString:=""
UnMatchedString:=""
;# 制作匹配的String
;# 从数组还原为换行文本(MatchedString)
loop % MatchedArray.MaxIndex()
{
MatchedString:=MatchedString "`r`n" MatchedArray[A_Index]
}
loop % UnMatchedArray.MaxIndex()
{
UnMatchedString:=UnMatchedString "`r`n" UnMatchedArray[A_Index]
}
;# 开始发送修改
;## 模式1留下不匹配的
if (ModifyMode=1){
Sleep 150
SendByClip(UnMatchedString)
Sleep 0
;## 如果开启剪切板写入,那就把剩下的放到上面
if (EnableWriteClip)
Clipboard:=MatchedString
}
;## 模式2留下匹配的
else if (ModifyMode=2){
Sleep 150
SendByClip(MatchedString)
Sleep 0
;## 如果开启剪切板写入,那就把剩下的放到上面
if (EnableWriteClip)
Clipboard:=UnMatchedString
}
;# 把两个字符串合并成一个大数组
TwoStringArray := [MatchedString,UnMatchedString]
;# 返回二维数组
return TwoStringArray
}
}
lib依赖库
;# RestoreClip的意思是,"还原剪切板",因为通过这个方法复制的时候,需要从剪贴板里走,开启这个的话,那么剪切板就还原成没操作之前的样子(应该是完全一样的,格式也不会丢失,因为用的是ClipboardAll)
SendByClip(var_string,HomeOrEnd:=0,LeftOrRight:=0,RestoreClip:=true,HomeOrEnd_AfterSending:=0,EnableTrayTip:=0){
local
if WinActive("ahk_class SciTEWindow"){
Sleep 0
ControlClick , Scintilla1,SciTE4AutoHotkey
ControlClick , Scintilla1,SciTE4AutoHotkey
;~ Send,{Esc}
}
Sleep 5
;## 简单模式:如果是简单模式的话(就是后面两个参数根本没填) 那就干脆直接发送并return 应该能节约不少时间
if ((HomeOrEnd+LeftOrRight)=0){
SendByClip_s1(var_string,RestoreClip)
return
}
;# 发送Home/End(!!! 这个是在发送之前移动)
;## 只有在不为零并且不为空的情况下才可以继续进行
if (HomeOrEnd!=0) AND (HomeOrEnd!=""){
;## 如果是1或者"Home"发送"Home"
if (HomeOrEnd=1) Or (HomeOrEnd="Home")
send,{Home}
;## 如果是-1或者"End"发送"End"
else if (HomeOrEnd=-1) Or (HomeOrEnd="End")
send,{End}
}
;# Home或End是在字符串没有发送之前send的 , Left或者Right是之后
SendByClip_s1(var_string,RestoreClip,EnableTrayTip)
;# 发送Home/End(!!! 这个是在发送之前移动)
;## 只有在不为零并且不为空的情况下才可以继续进行
if (HomeOrEnd_AfterSending!=0) AND (HomeOrEnd_AfterSending!=""){
;## 如果是1或者"Home"发送"Home"
if (HomeOrEnd_AfterSending=1) Or (HomeOrEnd_AfterSending="Home")
send,{Home}
;## 如果是-1或者"End"发送"End"
else if (HomeOrEnd_AfterSending=-1) Or (HomeOrEnd_AfterSending="End")
send,{End}
Sleep 30
}
;# 发送LeftOrRight(!!!Left或者Right是发送之后)
;## 只有在不为零并且不为空的情况下才可以继续进行
if (LeftOrRight!=0) AND (LeftOrRight!=""){
;## 检测一下输入的字符串符合哪种格式
L_RE := RegExMatch(LeftOrRight,"L[0-9]+")
R_RE := RegExMatch(LeftOrRight,"R[0-9]+")
;## 如果两种格式均不匹配,那么就返回错误
if (L_RE+R_RE=0)
throw Exception ("""LeftOrRight"" Parameter Error")
;## 如果有匹配的,那么就继续进行
;### 下面else块的作用就是搞清楚到底Left还是Right被匹配了,如果匹配成功的话,那就按次数发送
else{
;## 计算发送次数
;### 删除可能的L或R(根据模式)
if (L_RE){
times := StrReplace(LeftOrRight,"L", "")
Send,{Left %times%}
}
else{
times := StrReplace(LeftOrRight,"R", "")
Send,{Right %times%}
}
}
} ;# 发送LeftOrRight结束
return
}
;# 把纯发送单独拿出来了
SendByClip_s1(var_string,RestoreClip,EnableTrayTip:=0){
local
;# 先把剪切板上旧的给存起来
if (RestoreClip){
ClipboardOld = %ClipboardAll%
}
;把需要粘贴的赋值到剪切板,赋值后检测是否一致 。如果一致的话,那就输出;如果不一致,那么就延长时间,尝试5次
Loop,5
{
Sleep 35
Clipboard := ""
;至少停顿五毫秒,如果不行,那就延长时间
if(A_Index>1)
{
Sleep,% (A_Index*50)
}
Sleep 25
Clipboard := var_string
;~ 如果发现一致,就可以跳出循环
if(Clipboard=var_string)
{
break
}
}
Sleep 5
;~ ClipWait
send ^v
Sleep 150
;这个停顿可能是非常关键的,因为在有些软件里按下^v后可能还没反应过来呢,剪切板就已经变回去了,导致发送失败
;# 然后再把旧的给还原
if (RestoreClip){
Clipboard := ClipboardOld ; Restore previous contents of clipboard.
}
Sleep 5
if (EnableTrayTip)
TrayTip,%A_ScriptName% 提醒,剪切板中的内容已经成功被发送
return
}
;# 去除多余的空行(支持深度清洁,也就是不只是换行,段首空白符也一起干掉)
;# Remove all blank lines from the text in a variable:
RemoveAllBlankLines(MyString,EnableDeepClean:=false){
if (EnableDeepClean)
MyString:=RemoveBlankChar(MyString)
;# 这个意思是"多于1个(或者说2个以上)的换行符字符"串,全部替换为1个换行符
result := RegExReplace(MyString, "\R+\R", "`r`n")
return,%result%
}
;# 移除段首空白字符(除换行/回车/垂直制表符之外)
RemoveBlankChar(MyString){
local
;# 这个意思只要"换行符后面跟着空白字符"的字符串就,全部替换为1个换行符
;~ result := RegExReplace(MyString, "\R\s*", "`r`n")
;# 匹配"空格"+"换页符"+"水平制表符" 如果匹配全部的\s,那么容易误伤
result := RegExReplace(MyString, "\R[ \f\t]*", "`r`n")
return,%result%
}
/*
;# 这是个老的方案,先不用了(效果不如上面,差距很大很大)
RemoveAllBlankLines(MyString){
exitc:=0
;# 刚才查了一下,之所以只用第二个失败的原因就是,可能有些是`n而有些却是`r`n,正则表达式都可以匹配,所以第一个直接用是行的。但是为了彻底一点,我还是都用吧。原理我还没有搞清楚,以后有时间的话,仔细的研究研究。
;# 统一替换为`n了
Loop
{
;~ https://autohotkey.com/board/topic/115962-regex-to-remove-blank-lines/
StringReplace, MyString, MyString, `r`n`r`n, `r`n, UseErrorLevel
if ErrorLevel = 0 ; No more replacements needed.
exitc++
StringReplace, MyString, MyString, `n`n, `r`n, UseErrorLevel
if ErrorLevel = 0 ; No more replacements needed.
exitc++
if (exitc++>1)
break
}
return,%MyString%
}
*/
/*
;# checkString函数说明书
;## 功能介绍(默认下)
检查某字符串中是否含有某关键词(可以是多个,用|隔开即可) 如果有则return 1,没有return 0
;# 参数介绍
; ## CaseSensitive 默认是不区分大小写的,可以通过更改CaseSensitive改变
; ## ReturnKey 开启之后不返回1/0 如果检查到了之后,那就返回匹配的"TheKeys",否则就返回空""
; ## ReturnNumber
开启之后在"ReturnKey"不开启的情况下可以返回"TheKeys"匹配成功的次数(TheKeys数量>=次数>0)(因为如果开了返回次数,传过来的内容需要全部检查)
如果参数为"Mode2",则返回"TheKeys"在String中找到的所有次数的综合
举例子:Mode1(true)开启时 checkString("ABCCCC","C","Mode1") 结果是 1
Mode2开启时 checkString("ABCCCC","C","Mode2") 结果是 4
--------------要兼容("Mode1")这种写法 + 更新版本信息
; ## 这个函数的最大优点就是简便快捷,检查多个检查关键词的时候不需要用到数组什么的
;---------------------------------------------------------------------------------------------------------------
;# 版本信息
v0.5 :修复一个低级错误,由于true和false写翻了,所以在某些状况下,会出现结果正好相反的情况
v1.0:支持SimpleArray和String两种TheKeys(自动判断)
v1.5:进行判断的时候(用户还是可以输入的,因为要先转换一下)彻底放弃StringGroup,以后尽量的使用SimpleArray
*/
CheckString(HayStack,TheKeys,ReturnNumber:=false,ReturnKey:=false,CaseSensitive:=false){
local
;# 首先检查HayStack一下到底是Array还是String
ItIsObj:=IsObject(TheKeys)
;# 如果是String先转换一下
if (ItIsObj=false){
TheKeys:=StringGroupParseToSimpleArray(TheKeys,"`|",false,false)
ItIsObj:=IsObject(TheKeys)
if (ItIsObj=false)
throw Exception("ParaMeter TheKeys Error")
}
;# 默认不检查数量(速度快)
;## 如果不检查数量的话,那么就运行这个
if (returnNumber=false) {
loop,% TheKeys.Length()
{
if (InStr(HayStack,TheKeys[A_Index] ,CaseSensitive,1,1)){
;# 一旦找得到就返回return或者字符串
;## 要求返回字符串,那么就直接返回字符串 ,如果没有要求,那就返回 true
if (returnKey){
return TheKeys[A_Index]
}
else
return true
}
}
;## 跳出循环体,只有一个可能性就是所有的TheKeys都没有匹配上,这样的话就会返回""(空字符串)或者是false
; ## 如果检查不到就反空字串
if (returnKey)
return, ""
return false
}
;# 检查数量 一个是返回数量 只要返回数量了,就不能再返回(匹配到的字符串) (以后可以设置为返回数组,但是今天用不到,先算了吧)
;# Mode1和true一个效果
else if (returnNumber=true) || (returnNumber="Mode1") || (returnNumber="Mode2") {
;# 如果请求匹配大小写,那么就打开
if (CaseSensitive)
StringCaseSense,On
TheNumber:=0
;# 这是那个更精确的数据(Mode2)
TheNumber2:=0
loop,% TheKeys.Length()
{
;~ if(InStr(HayStack,TheKeys[A_Index],CaseSensitive,1,1))
;# 采用替换的方法,这样我们就可以获得次数
;~ temp := StrReplace(Haystack, TheKeys[A_Index] ,% TheKeys[A_Index] "$", OutputVarCount, -1)
temp := StrReplace(Haystack, TheKeys[A_Index] ,TheKeys[A_Index], OutputVarCount, -1)
if (OutputVarCount){
TheNumber2+=OutputVarCount
TheNumber++
}
}
;# 如果请求匹配大小写,匹配结束之后就关闭
if (CaseSensitive)
StringCaseSense,Off
if (returnNumber="Mode2")
return TheNumber2
else if (returnNumber=true) || (returnNumber="Mode1")
return TheNumber
else
throw Exception("Mode Error")
}
}
关于
如果您发现“库工作不正常”或“有更好的解决思路”,欢迎您和我交流,QQ2531574300。O(∩_∩)O~
End
心如止水是Java/AHK的持续学习者,很欢迎您来和我探讨Java/AHK问题。 QQ:2531574300 ^_^
更多文章
[专栏] AHK程序设计 - SegmentFault 思否(优先持续更新)
[基础] [GIF动图] 绕过中文输入法发送文本的3种方法)
[基础] AHK函数对象系列-绑定函数对象
[AHK-lib分享] 用指定程序批量打开文档
[基础] 代码语句与代码块