字符串处理在多数编程语言中都是重头戏,AHK 自然也不例外。AHK 在字符串处理方面还是很灵活的,如果掌握好了,写起代码来会事半功倍。本文先介绍最常用的操作:拼接和遍历。

字符串拼接

拼接恐怕是最常用的操作了,在 AHK 中也非常简单,直接将两个字符串用空格隔开就可以了。

a := "abc"
b := 100
c := "def"
d := 123.456
e := 200

; f 的值是字符串 abc100anddef123.456
f := a b "and" c d
; g 的值是字符串 100200
g := b e

不管是字符串、整数还是浮点数,都可以用空格拼接成一个字符串。更神奇的是,空格可以和其他算术运算符一起使用。

a := 100
b := 200

; c 的值是 100150
c := a b - 50

其实 AHK 中整数 100200 和 字符串 "100200" 是没有区别的,当整数用的时候就是 100200,当字符串用的时候就是 "100200",当然内部实现上会有一些优化。如果感觉无法接受的话,也可以认为整数和字符串是有区别的,在实际使用中会自动相互转换。

实际上,AHK 中 .(点运算符)是专门用来拼接字符串的,在某些情况还是不能省略的。

a := 300
b := 200

; c 的值是 100
c := a - b

; d 的值是 300-200
d := a . - b

正因为空格可以和其他算术运算符一起使用,使用起来可以很灵活,为了避免歧义,空格只有在必要的情况(即这个表达式没有其他的解释办法时)才起拼接作用。

子字符串遍历

还有一个非常常见的操作,是遍历一个字符串的子字符串。Loop, Parse 是专门用来做这个的。

Loop, Parse, InputVar [, Delimiters, OmitChars]

其中 InputVar 是变量名,不需要加 %。Delimiters 是分隔符,OmitChars 是要忽略的字符。

最简单的场景就是遍历字符串中的每一个字符。

text := "abcd"

Loop, Parse, text
{
    ; 依次弹出
    ; a
    ; b
    ; c
    ; d
    MsgBox, %A_LoopField%
}

Delimiters 和 OmitChars 都省略的情况,就是遍历字符串中的每一个字符。

另外一个典型场景是依次处理一段文字的每一行。

text =
(
line1
line2
line3
)

Loop, Parse, text, `n, `r
{
    ; 依次弹出
    ; line1
    ; line2
    ; line3
    MsgBox, %A_LoopField%
}

这里 Delimiters 是 `n。`r 又是什么呢?在类 UNIX 操作系统中,文本中的换行符就是 `n,但在 Windows 中,换行符是 `r`n。如果处理一段换行符是 `r`n 的文本,直接用 `n 分隔,会保留多余的 `r,所以设置 OmitChars 为 `r 可以将其去掉。可能有不仔细的朋友认为 Loop, Parse, text, \n, `r 是将字符串同时按 \n 和 `r 来分隔,这是错误的,`n 和 `r 的顺序也不能颠倒。

除了按换行符,我们也经常需要按其他符号分隔字符串,比如按空格,按逗号等,就大同小异了。但需要注意空格和逗号有点特殊,因为它们是特殊符号,写法有一些特别。

text := "a b,c d:xxx"

Loop, Parse, text, %A_Space%
{
    ; 依次弹出
    ; a
    ; b,c
    ; d:xxx
    MsgBox, %A_LoopField%
}

Loop, Parse, text, `,
{
    ; 依次弹出
    ; a b
    ; c d:xxx
    MsgBox, %A_LoopField%
}

Loop, Parse, text, :
{
    ; 依次弹出
    ; a b,c d
    ; xxx
    MsgBox, %A_LoopField%
}

这里空格用的是 %A_Space%,A_Space 是一个 AHK 的内部变量,这样需要用 % 取该变量的值。`, 是用转义的方法取到的逗号字符,因为直接写逗号会被认为是参数的分隔符。类似的还有 `t 或者 %A_Tab% 是 Tab 等等,如果一个字符直接写会报语法错误,那么通常在前边加个 ` 就可以了。以后我也会专门写文章介绍转义字符。至于冒号,就没有什么特别,直接写就可以了。

有些情况我们需要按字符串分隔,而不是按字符分隔,比如:

text := "abc()bcd(cde"

需要按 () 分隔 text。需要注意,这种情况这样的写法就是错误的了:

text := "abc()bcd(cde"

Loop, Parse, text, (, )
{
    ; 依次弹出
    ; abc
    ; bcd
    ; cde
    MsgBox, %A_LoopField%
}

一个可行的办法,是先将字符串中的 () 替换成一个字符串里没有的特殊字符,比如 @,然后再用这个特殊字符作为分隔符:

text := "abc()bcd(cde"

; StrReplace 函数是用来替换字符串的,我们以后再详细了解
text := StrReplace(text, "()", "@")

Loop, Parse, text, @
{
    ; 依次弹出
    ; abc
    ; bcd(cde
    MsgBox, %A_LoopField%
}

更多内容

除了拼接和遍历字符串,我们还需要进行查找、替换、匹配、分隔、计算长度等操作,这涉及数量较多的字符串处理函数,以后我们再详细了解。