仅靠正则表达式无法做到这一点。但是,可以使用正则表达式 + 状态解析来完成。
根据您的示例中可能出现的语法情况,我整理了一个完成这项工作的脚本。我用 Python 编写了它,因为我比 PHP 更熟悉这种语言,但是如果 Python 无法用于此任务,代码 + cmets 应该足够清晰,以便有人将其转换为 PHP。
#!/usr/bin/env python
import fileinput
import re
# Values you might want to modify
filename = "test.au3"
replacementFunctionName = "get_string"
replacementForConcatenator = ","
# Regexes to identify raw AutoIt elements
string = r"""(?:"(?:[^"]|"(?="))*"|'(?:[^']|'(?='))*')""" # triple quotes is just Python
macro = r"@\w+" # the prefix r makes the \ a literal (in the string, not the regex)
variable = r"\$\w+"
concatenator = r"\s*&\s*"
# Regexes to identify compound AutoIt elements
nonConcatenator = "(?:" + string + "|" + macro + "|" + variable + ")"
capturingNonConcatenator = "(" + string + "|" + macro + "|" + variable + ")"
zeroOrMoreConcatenatedNonConcatenators = "(?:" + concatenator + nonConcatenator + ")" + "*"
# The combined search regex and its compiled form
search = string + zeroOrMoreConcatenatedNonConcatenators
searchRe = re.compile(search) # compiling lets us specify a start index for searches
# Process file in place
count = 0 # used to correctly number AutoIt string literal instances
for line in fileinput.input(filename, inplace=True):
newLine = ""
# Convert old line to new line
indexInLine = 0
matchOfSearchRe = searchRe.search(line, indexInLine)
while matchOfSearchRe is not None:
matchReplacement = ""
# Replace each AutoIt string in matched substring with number
# and replace each concatenator with a comma
elementsOfMatch = re.split(capturingNonConcatenator, matchOfSearchRe.group(0))
for elem in elementsOfMatch:
if re.match(string, elem):
count += 1
matchReplacement += str(count)
elif re.match(concatenator, elem):
matchReplacement += replacementForConcatenator
else:
matchReplacement += elem
# Place modified contents of match in a replacement function call
matchReplacement = replacementFunctionName + "(" + matchReplacement + ")"
# Append most recently skipped region before match and replacement for match
newLine += line[indexInLine:matchOfSearchRe.start()]
newLine += matchReplacement
# Update loop control variables
indexInLine = matchOfSearchRe.end()
matchOfSearchRe = searchRe.search(line, indexInLine)
# Append rest of line after final match
newLine += line[indexInLine:]
# Replace old line in filename with new line in place
print(newLine.rstrip())
经过粗略测试,此脚本已转换
;This is autoit
$string1 = "This is a test string" & @crlf & "Wow, autoit syntax!"
$string2 = "This string has a var. Var1=" & $var1
$wow = random_function("Another string") & "this is getting complex"
magic_function("var1=" & $var1 & @crlf & "other var=" & $var2)
$multivar = "This string has 2 vars: var1=" & $var1 & " var2=" & $var2
到
;This is autoit
$string1 = get_string(1,@crlf,2)
$string2 = get_string(3,$var1)
$wow = random_function(get_string(4)) & get_string(5)
magic_function(get_string(6,$var1,@crlf,7,$var2))
$multivar = get_string(8,$var1,9,$var2)
如果可能的语法情况比您的示例中的更多样化,则不能保证此脚本可以正常工作。但是,可以通过添加或更改“识别原始 AutoIt 元素的正则表达式”和相关的“识别复合 AutoIt 元素的正则表达式”来修改它以满足您的需求。任何修改都将收集在 search 变量中,因此脚本主体中不需要更改任何其他内容。
请注意,我在测试用例中修改了您的示例输入。您的示例的最后一行似乎有两个语法错误:缺少& 和额外的"。