用 Ruby 处理 Vim 中的选定内容并替换文本

4

如何通过 Ruby 脚本运行选定内容并将其替换为该脚本的最后返回值?

例如,我有以下几行代码:

12|22|33

我想将这些数字翻倍

24|44|66

我不知道 vim 的方法(但如果有人能帮忙,我想知道),但我知道 Ruby 的方法。

# assuming the text is in variable "line"
line.split("|").map(&:to_i).map { |no| no*2 }.join("|")

当然,我可以编写一个接受参数的Ruby脚本,并使用:!my_script.rb%调用它,但我想直接在vim中提供Ruby代码。

2个回答

4
你可以使用:h s /\\= ,它允许你对匹配项进行计算:
:s/\d\+/\=submatch(0)*2/g

2

Ruby有一个-e选项,当提供少量代码时非常有用:

:!ruby -e 'puts $_.split("|").map(&:to_i).map { |no| no*2 }.join("|") while gets'

如果您只想针对单行执行代码,则可以省略while循环:

:!ruby -e 'puts gets.split("|").map(&:to_i).map { |no| no*2 }.join("|")'

执行终端命令时,所选行将作为标准输入发送给它。gets将从标准输入读取。 Kernel#gets文档:

gets(sep=$/ [, getline_args]) → string or nil click to toggle source

gets(limit [, getline_args]) → string or nil

gets(sep, limit [, getline_args]) → string or nil

Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line. Returns nil at end of file. The optional argument specifies the record separator. The separator is included with the contents of each record. A separator of nil reads the entire contents, and a zero-length separator reads the input one paragraph at a time, where paragraphs are divided by two consecutive newlines. If the first argument is an integer, or optional second argument is given, the returning string would not be longer than the given value in bytes. If multiple filenames are present in ARGV, gets(nil) will read the contents one file at a time.

ARGV << "testfile"
print while gets

produces:

This is line one
This is line two
This is line three
And so on...

The style of programming using $_ as an implicit parameter is gradually losing favor in the Ruby community.

您可以使用-p-n标志来缩短上述代码,这将在一个while gets循环内包装代码:

:!ruby -ne 'puts $_.split("|").map(&:to_i).map { |no| no*2 }.join("|")'

或者

:!ruby -pe '$_ = $_.split("|").map(&:to_i).map { |no| no*2 }.join("|")'

来自man ruby页面:

     -n             Causes Ruby to assume the following loop around your
                    script, which makes it iterate over file name arguments
                    somewhat like sed -n or awk.

                          while gets
                            ...
                          end

     -p             Acts mostly same as -n switch, but print the value of
                    variable $_ at the each end of the loop.  For example:

                          % echo matz | ruby -p -e '$_.tr! "a-z", "A-Z"'
                          MATZ

谢谢,我遗漏的部分是gets方法,它可以读取光标下的当前行。 - 23tux
1
你也可以使用 -p 标志和 $_ 变量来实现这个功能。 - Hauleth
@Hauleth 我忘记它们了,因为我不经常使用这个模式。但是它们可以大大缩短代码。已更新答案。 - 3limin4t0r
值得注意的是,!作为一个普通命令是一个操作符,它会预先填充范围。 - D. Ben Knoble

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接