Vimscript:正则表达式在 :s 中有效,但在替代()中无效

发布于 2024-12-08 23:52:11 字数 344 浏览 0 评论 0原文

如果我将 :ls 的输出粘贴到缓冲区中,该命令

:%s/.*\(\".*\"\).*/\1/

会将该输出减少为仅文件路径。想要在变量中实现这个结果,我做了

:redir => x|silent :ls|redir END
:let y = substitute(x, ".*\(\".*\"\).*", "\1", "g")

什么,但什么也没完成,y 与 x 相同。我已经尝试了该替代命令的无数变体,只得到相同的结果,或者一堆错误消息。我应该如何指定它?

If I paste the output of :ls into a buffer, the command

:%s/.*\(\".*\"\).*/\1/

reduces that output to just the file paths. Wanting to achieve that result in a variable, I did

:redir => x|silent :ls|redir END
:let y = substitute(x, ".*\(\".*\"\).*", "\1", "g")

which accomplished absolutely nothing, y is identical to x. I've tried umpteen variations on that substitute command, getting only the same result, or a bunch of error messages. How should I be specifying it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谢绝鈎搭 2024-12-15 23:52:11

您需要转义引号中的反斜杠。将 \\(\\\"substitute() 结合使用。

You need to escape backslashes in quotes. Use \\( and \\\" with substitute().

蛮可爱 2024-12-15 23:52:11

你有两个错误:第一个错误已经被@Radu提到过,第二个错误是由于在 substitute() 中换行符匹配 . ,而在 :s< /code> 事实并非如此。这就是为什么“只提供最后一场比赛”。我可以使用 :redir:lssubstitute() 发布正确的解决方案,但建议如下:

let buflist=map(filter(range(1, bufnr('

如果您想要输出几乎相同对于 :ls 所具有的内容,请尝试将 bufname(v:val) 替换为 BufName(v:val)

function BufName(bnr)
    let bn=bufname(a:bnr)
    let bt=getbufvar(a:bnr, '&buftype')
    if empty(bn)
        return (empty(bt)?('[No Name]'):('[Scratch]'))
    elseif empty(bt)
        " This won't produce names like ../file, while :ls will "
        return fnamemodify(bn, ':~:.')
    elseif bt is# 'help'
        return fnamemodify(bn, ':t')
    else
        return bn
    endif
endfunction

上面的命令会给您留下一个字符串列表。如果您想使用换行符分隔的“列表”,请使用

let bufliststr=join(buflist, "\n")

如果您仍想使用 substitute(),请参阅 :h /[]

)), 'buflisted(v:val)'), 'bufname(v:val)')

如果您想要输出几乎相同对于 :ls 所具有的内容,请尝试将 bufname(v:val) 替换为 BufName(v:val)

上面的命令会给您留下一个字符串列表。如果您想使用换行符分隔的“列表”,请使用

如果您仍想使用 substitute(),请参阅 :h /[]

You have two errors: first was already mentioned by @Radu, second is arises from the fact that in substitute() newline matches ., while in :s it is not. That is why «only the final match is delivered». I can post a correct solution using :redir, :ls and substitute(), but instead suggest the following:

let buflist=map(filter(range(1, bufnr('

If you want output almost identical to what :ls has, try replacing bufname(v:val) with BufName(v:val):

function BufName(bnr)
    let bn=bufname(a:bnr)
    let bt=getbufvar(a:bnr, '&buftype')
    if empty(bn)
        return (empty(bt)?('[No Name]'):('[Scratch]'))
    elseif empty(bt)
        " This won't produce names like ../file, while :ls will "
        return fnamemodify(bn, ':~:.')
    elseif bt is# 'help'
        return fnamemodify(bn, ':t')
    else
        return bn
    endif
endfunction

The above command leaves you with a list of strings. If you want to have a newline-separated «list» instead, use

let bufliststr=join(buflist, "\n")

If you still want to use substitute(), see :h /[].

)), 'buflisted(v:val)'), 'bufname(v:val)')

If you want output almost identical to what :ls has, try replacing bufname(v:val) with BufName(v:val):

The above command leaves you with a list of strings. If you want to have a newline-separated «list» instead, use

If you still want to use substitute(), see :h /[].

迷乱花海 2024-12-15 23:52:11

变量 x 包含

1 #    "~/Session.vim"                line 5
2      "~/.vimrc"                     line 34
3      ".vim/vscripts/makesess.vim"   line 4
4      "~/Documents/vimcht"           line 62
5      "~/.fluxbox/startup"           line 5
6      "~/Documents/Notes"            line 2604
7      "~/Documents/bashcht"          line 21
8 %a   "junk"                         line 10

根据我对 :h /[] 的阅读,特别是“...没有“_”或“\n”集合与行尾不匹配...”,那么

:let y = ""
:let y = substitute(x, '[.]*\("[.]*"\)[.]*', '\1', "g")

应该完成工作。但它的表现

"junk"

与没有 [] 时一样。
然后我尝试

:let y = ""
:let y = substitute(x, '[^\n]*\("[^\n]*"\)[^\n]*', '\1', "g")

并得到了完全相同的结果。

显然,vim 在内部不使用实际的换行符,无论是变量还是寄存器。因此它将变量视为单行。这导致我找到了这个解决方案,

:let y = substitute(x, '[^"]*\("[^"]\+"\)[^"]*', ':tabe \1\n', 'g')

产生 y 包含

:tabe "~/Session.vim"
:tabe "~/.vimrc"
:tabe ".vim/vscripts/makesess.vim"
:tabe "~/Documents/vimcht"
:tabe "~/.fluxbox/startup"
:tabe "~/Documents/Notes"
:tabe "~/Documents/bashcht"
:tabe "junk"

所需的内容以形成我的 Session.vim 文件

The variable x contains

1 #    "~/Session.vim"                line 5
2      "~/.vimrc"                     line 34
3      ".vim/vscripts/makesess.vim"   line 4
4      "~/Documents/vimcht"           line 62
5      "~/.fluxbox/startup"           line 5
6      "~/Documents/Notes"            line 2604
7      "~/Documents/bashcht"          line 21
8 %a   "junk"                         line 10

By my reading of :h /[], particularly "...Without the "_" or "\n" the collection does not match an end-of-line...", then

:let y = ""
:let y = substitute(x, '[.]*\("[.]*"\)[.]*', '\1', "g")

should have done the job. But it delivered

"junk"

just as it did without the [].
I then tried

:let y = ""
:let y = substitute(x, '[^\n]*\("[^\n]*"\)[^\n]*', '\1', "g")

and got exactly the same result.

Clearly vim does not use the actual newline character internally, neither for variables nor for registers. So it treats a variable as a single line. Which led me to this solution

:let y = substitute(x, '[^"]*\("[^"]\+"\)[^"]*', ':tabe \1\n', 'g')

yielding y containing

:tabe "~/Session.vim"
:tabe "~/.vimrc"
:tabe ".vim/vscripts/makesess.vim"
:tabe "~/Documents/vimcht"
:tabe "~/.fluxbox/startup"
:tabe "~/Documents/Notes"
:tabe "~/Documents/bashcht"
:tabe "junk"

as desired to form my Session.vim file

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文