获取带有回车符的可分析字符串

时间:2018-07-21 16:46:19

标签: vim

有时我会使用string()函数来生成可分析的字符串。

例如,:echo string("hello world")显示:

'hello world'

但是,如果我将真实的回车符添加到字符串中,结果将变得无法分析,这仅仅是因为 回车不进行转换。

例如,:echo string("hello\nworld")显示:

'hello
world'

我原本期望:

"hello\nworld"

是否可以在不编写专用函数的情况下获得 any 字符串的可解析版本?


编辑

更准确地说,我需要与:execute命令一起使用“可分析”的字符串,以便创建可自定义的映射。基本思想是即使在a:toinsert参数中有一些CR,也能够使用以下代码:

function! InsertMapping(lhs, toinsert)
    let l:rhs = printf('<c-r>=%s<cr>', string(a:toinsert))
    exe 'inoremap' a:lhs l:rhs
endf

" This call is working:
call InsertMapping('<c-r><c-e>', "hello world")

" This one throws an error:
call InsertMapping('<c-r><c-e>', "hello\nworld")
" E492: Not an editor command: world')<cr>

实际上,对InsertMapping()的最后一次调用将尝试执行:

inoremap <c-r><c-e> <c-r>='hello
world'<cr>

当然,我需要执行:

inoremap <c-r><c-e> <c-r>="hello\nworld"<cr>

请注意,我需要保留<c-r>=,因为我的实际用例更加复杂,并且需要一些函数调用;因此无法像这样简化映射:

inoremap <c-r><c-e> hello<cr>world

3 个答案:

答案 0 :(得分:0)

不知道您究竟是什么意思“可分析”。如果您想使用eval()来获取原始字符串值,则可以使用它。您会看到真正的换行符是由于echo()函数而被打印出来的,它将\n扩展为一个换行符。

尝试一下:

let a="hi\nworld"
echo a==eval(string(a))
echo a==eval(string("hi\nworld"))

两者都将返回1(true)。因此它是“可分析的”。

如果我不理解您的“可分析”的含义,请举一些例子。

答案 1 :(得分:0)

我终于写了一个专用的函数来对vim字符串进行字符串化;它远非完美,但它将为所有测试案例提供“正确”的输出。如果在字符串中根本没有什么特别的地方,它会返回单引号的字符串,这在某些极少数情况下可能会稍微提高性能。

代码如下:

let s:specials = {
    \ "\b":'\b', "\e":'\e', "\f":'\f', "\n":'\n',
    \ "\r":'\r', "\t":'\t', "\\":'\\', "\"":'\"',
\}

function! Stringify(source)
    let output = ''
    let string_is_special = v:false

    for i in range(strlen(a:source))
        let char = a:source[i]
        let ascii = char2nr(char)

        let char_is_special = v:false
        for [key, str] in items(s:specials)
            if char == key
                let output .= str
                let char_is_special = v:true
                let string_is_special = v:true
                break
            endif
        endfor

        if !char_is_special
            if ascii < 32
                let output .= printf('\x%02x', ascii)
                let string_is_special = v:true
            else
                let output .= char
            endif
        endif
    endfor

    return printf(string_is_special ? '"%s"' : "'%s'", output)
endf

以下是一些快速测试:

let tests = [
    \ "simple string",
    \ 'back \ slash',
    \ "carriage \n return",
    \ "utf8 frénçh àccènts",
    \ "\x47\x6e\x75",
    \ "ctrl-w special key: \<c-w>",
\ ]

for s in tests
    echo Stringify(s)
endfor

这是测试输出:

'simple string'
"back \\ slash"
"carriage \n return"
'utf8 frénçh àccènts'
'Gnu'
"ctrl-w special key: \x17"

答案 2 :(得分:-1)

在Vim中,单引号和双引号的行为不同。

在双引号之间,会解释特殊字符,例如\n,因此:

"hello\nworld"

成为:

hello
world

,您必须将\加倍才能实际获得\n

"hello\\nworld"

在单引号之间,不解释特殊字符,因此:

'hello\nworld'

成为:

hello\nworld

所有这些都在:help expr-":help expr-'下进行了解释。