我猜你被引号所困惑,因为
string.gsub
可以替换反斜杠字符:
C:...> lua
Lua 5.1.4 版权所有(C) 1994-2008 Lua.org, PUC-Rio
> a="test\\\\ttest"
> =a
test\\ttest
> =a:gsub([[\\]],[[\]])
test\ttest 1
>
在双引号和单引号字符串中,反斜杠用作字符转义符,但在使用
[[...]]
表示的长字符串中不会。在通常的字符串常量中,反斜杠消耗一个或多个后续字符,并将整个序列替换为内部字符串值中的单个字节。因此,
"\\"
是包含一个反斜杠的单字节字符串,
"\"
是语法错误,
"\""
是包含双引号的单字节字符串。
增加混乱的是,Lua模式(由
string.gsub
及其衍生函数理解)使用
%
字符进行引用和命名特殊模式。这是Lua模式与其他语言支持的正则表达式之间较为明显的差异之一。对于Lua模式而言,反斜杠只是一个普通的字符。
因此,在上述设置
a
的值时,我使用了额外的反斜杠,使得字符串值总共有两个。我也可以这样写:
a=[[test\\ttest]]
。调用
gsub
时,简单模式将双倍反斜杠替换为单个反斜杠。可以看到,它成功了,结果是字符串
test\ttest
(以及作为第二个返回值的匹配计数)。
简而言之,在问题中所要求的替换“只是起作用”的预期效果。
但是,读懂了你的意思,似乎并不完全是这样。你似乎试图将字符串
test\\ttest
转换为
test<TAB>test
。如果这是你想要的单一转换,那么就像这样写:
a:gsub([[\\t]],"\t")
。(请注意,我使用引号,以便字符串文字将解释
\t
为替换值中的ASCII字符。)
更通用的情况则更加困难,因为你不仅必须处理制表符、响铃符、退格符、回车符、换行符等常规单字母转义,还必须处理一到三位十进制码序列。
更新:编写一个处理所有反斜杠转义的函数,就像Lua编译器处理字符串字面量一样,太强烈的诱惑了。
function unbackslashed(s)
local ch = {
["\\a"] = '\\007',
["\\b"] = '\\008',
["\\f"] = '\\012',
["\\n"] = '\\010',
["\\r"] = '\\013',
["\\t"] = '\\009',
["\\v"] = '\\011',
["\\\n"] = '\\010',
["\\\\"] = '\\092',
["\\'"] = '\\039',
['\\"'] = '\\034',
}
return s:gsub("(\\.)", ch)
:gsub("\\(%d%d?%d?)", function(n)
return string.char(tonumber(n))
end)
end
这样的函数在解析用户提供的文本并希望处理用户提供的文本中的反斜杠转义时非常有用。字符串文字应该已经由编译器处理了。
另一个需要注意的地方是,如果你发现自己有部分翻译不完整的字符串,那么实际上可能会遭受设计缺乏清晰性的困扰。实际上需要这样的函数而不是解析用户输入之外的一种指示,这表明你的设计可能存在更深层次的问题。
函数"unbackslashed"的工作原理是首先用相应的数字形式替换所有识别出的以反斜杠后跟单个字符的序列形式出现的序列。第二轮将所有数字形式转换为它们的文字字符形式。之所以需要两轮,是因为string.gsub所理解的字符串模式不支持全面的正则表达式解析器所支持的备选符号。否则,匹配模式可以写成类似于Perl的"/\\([0-9]{1-3})|\\(.)/",并在一次转换中执行替换。
\t
,而是一个水平制表符。您的“unbackslashed”函数也不是我要求的。查看原帖,我明确表示我不想用“\t”替换“\t”,而是用“\”替换“\”。 然而,在该函数中使用ASCII代码和string.char()并没有必要,仅使用ASCII字符就像s:gsub("\\t","\t")
一样可以工作。 这不是我的问题的答案。 - noizeunbackslashed
函数模拟了Lua编译器对字符串字面量的处理方式,并可用于将包含\t
的字符串转换为包含实际水平制表符的字符串。 - RBerteig