3

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

目的很明确:我想输出\t转义序列(水平选项卡),而现在它只是输出为纯文本\t

也很清楚我不能使用:

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

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

请不要说要做:

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

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

4

1 回答 1

5

我怀疑您对引用感到困惑,因为string.gsub可以替换反斜杠字符:

C:...> lua
Lua 5.1.4 版权所有 (C) 1994-2008 Lua.org, PUC-Rio
> a="测试\\\\ttest"
> =一个
测试\\ttest
> =a:gsub([[\\]],[[\]])
测试\测试 1
>

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

string.gsub更令人困惑的是, (及其兄弟)所理解的 Lua 模式使用%字符来引用和命名特殊模式。这是 Lua 模式与其他语言支持的正则表达式之间更明显的区别之一。对于 Lua 模式来说,反斜杠只是一个普通字符。

因此,当我设置a上面的值时,我使用了额外的反斜杠来使字符串值总共有两个。我本可以写出a=[[test\\ttest]]同样的效果。调用gsub是用简单的模式编写的,将双反斜杠替换为单反斜杠。可以看出,它成功了,结果是字符串test\ttest(以及作为第二个返回值的匹配计数)。

简而言之,您在“正常工作”的问题中要求的替换按预期进行。

但是在字里行间阅读,这并不是您想要的。您似乎正在尝试将字符串转换test\\ttesttest<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})|\\(.)/并且一次执行替换。

于 2013-11-13T19:48:00.927 回答