在Lua中用单反斜杠替换输入的双反斜杠

时间:2013-11-13 18:30:24

标签: lua escaping

假设我有str变量,我为其分配值test\\ttest(或者它实际上可能只是\\,对于这种情况)。我想要做的是用单个反斜杠代替双反斜杠。

目的很明确:我想输出\t转义序列(水平标签),而现在它只是以纯文本\t输出。

很明显,我不能使用:

str:gsub("\\","\")

因为这会导致语法错误,将\"识别为转义序列。我尝试了所有可以出来的方式。我也尝试过使用loadstring()(以及嵌套的loadstring()调用)但它也失败了。

请不要说:

str:gsub("\\t","\t")

当然,它会起作用,但这不是我需要的。我需要用一个反斜杠替换双反斜杠。

1 个答案:

答案 0 :(得分:5)

我怀疑你被引用搞糊涂了,因为string.gsub可以替换反斜杠字符:

C:...> lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> a="test\\\\ttest"
> =a
test\\ttest
> =a:gsub([[\\]],[[\]])
test\ttest       1
>

反斜杠用作双引号和单引号字符串中的字符转义符,但不是用[[...]]符号编写的长字符串。在通常的字符串常量中,反斜杠使用一个或多个后续字符,并用内部字符串值中的单个字节替换整个序列。因此"\\"是包含单个反斜杠的单字节字符串,"\"是语法错误,"\""是包含双引号的单字节字符串。

令人困惑的是,string.gsub(及其兄弟姐妹)理解的Lua模式使用%个字符来引用和命名特殊模式。这是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', --'\a' alarm             Ctrl+G BEL
        ["\\b"] = '\\008', --'\b' backspace         Ctrl+H BS
        ["\\f"] = '\\012', --'\f' formfeed          Ctrl+L FF
        ["\\n"] = '\\010', --'\n' newline           Ctrl+J LF
        ["\\r"] = '\\013', --'\r' carriage return   Ctrl+M CR
        ["\\t"] = '\\009', --'\t' horizontal tab    Ctrl+I HT
        ["\\v"] = '\\011', --'\v' vertical tab      Ctrl+K VT
        ["\\\n"] = '\\010',--     newline
        ["\\\\"] = '\\092',--     backslash
        ["\\'"] = '\\039', --     apostrophe
        ['\\"'] = '\\034', --     quote
    }
    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})|\\(.)/类似,并且替换在一次传递中执行。