In the article, Vim Regular Expressions, Oleg Raisky gives the following command to reduce multiple blank lines to a single blank:
在文章中,Vim正则表达式,Oleg Raisky给出了以下命令,可以将多个空行减少为一个空白:
:g/^$/,/./-j
Can someone please describe how this works?
有人能描述一下这是怎么回事吗?
I know :g
command and regular expressions. But I didn't understand what the part /,/./-j
does.
我知道:g命令和正则表达式。但是我不明白那部分是什么。/ - j。
1 个解决方案
#1
49
It really is quite ingenious. Let's break it down. The ex
command
这真的很有创意。让我们休息一下。前命令
g/^$/xyzzy
will search for all empty lines and execute the xyzzy
command (an arbitrary ex
command) on each of them.
将搜索所有空行并在每个空行上执行xyzzy命令(任意的ex命令)。
The tricky bit here is that the xyzzy
command in your case is yet another substitute command:
这里有点棘手的一点是,在您的案例中,xyzzy命令是另一个替代命令:
,/./-j
The ,/./-
specifies a range. This is of the form <start>,<end>
and, because there's nothing before the comma, it assumes the current line (the one where you found the blank line) is the start.
,/。/ -指定一个范围。这是
After the comma is /./-
which means search for the next character (.
means any character) then back up one line (/./-
is short for /./-1
since the one is implied if no value is given). You'll find that pattern .
on the first non-blank line following the one you're operating on.
逗号后面是/。/-这意味着搜索下一个字符(。表示任何字符)然后备份一行(/。/- is short for /。/-1,因为如果没有给定的值,就暗示了这一点。你会发现这种模式。在第一个非空行跟踪您正在操作的一个。
In other words, the end of the range is the last blank line after or at the one you're currently operating on.
换句话说,这个范围的末尾是您当前操作的最后一个空行。
Then you execute a join over that range.
然后在该范围内执行联接。
If the start and the end of the range were equal (only one blank line was in the section), join does nothing. If they're not equal, join will join them all up.
如果这个范围的开始和结束是相等的(只有一个空行在这一节),join什么也不做。如果它们不相等,join会将它们全部连接起来。
That's the way in which it combines multiple blank lines into one.
这就是它将多个空行合并成一个的方法。
Lets look at an example (line numbers are not in the file):
让我们看一个例子(行号不在文件中):
1 Line 1
2
3 Line 3
4 Line 4
5
6
7
8
9 Line 9
The :g
command will find all blank lines and perform its operation on them (lines 2, 5, 6, 7 and 8).
g命令将找到所有的空行并对它们执行操作(第2、5、6、7和8行)。
For line 2, ,/./-j
will set up a range from 2 to 2 (next .
found on line 3 then subtract 1). A join on the range 2,2 does nothing.
第2行,,/。/-j将设置一个范围从2到2。在第3行找到,然后减去1)。
For line 5, ,/./-j
will set up a range from 5 to 8 (next .
found on line 9 then subtract 1). A join on the range 5,8 will join all those lines together.
第5行,,/。/-j将设置一个范围从5到8(下一个。在第9行找到,然后减去1)。
I'm not entirely certain about this but I think the operation may not be performed on lines that disappear as part of an earlier operation. That's because it would make no sense to process lines that have been deleted earlier in the cycle.
我并不完全确定这一点,但我认为这一操作可能不会在之前的操作中消失。这是因为对在循环中早期被删除的行进行处理是毫无意义的。
In other words, because lines 6 through 8 are deleted (combined with line 5), the global command doesn't operate on them after that. I base that on nothing more than the fact that the vim documentation states a two-pass algorithm, one to mark the lines, one to perform the operation.
换句话说,由于第6行到第8行被删除(与第5行合并),因此全局命令在此之后不会对它们进行操作。我的基础是vim文档说明了一个两遍算法,一个用来标记行,一个用于执行操作。
I may be wrong on that point (it wouldn't be the first time) but it's an implementation detail which doesn't affect the functionality.
在这一点上,我可能错了(这不是第一次),但它是一个实现细节,不会影响功能。
#1
49
It really is quite ingenious. Let's break it down. The ex
command
这真的很有创意。让我们休息一下。前命令
g/^$/xyzzy
will search for all empty lines and execute the xyzzy
command (an arbitrary ex
command) on each of them.
将搜索所有空行并在每个空行上执行xyzzy命令(任意的ex命令)。
The tricky bit here is that the xyzzy
command in your case is yet another substitute command:
这里有点棘手的一点是,在您的案例中,xyzzy命令是另一个替代命令:
,/./-j
The ,/./-
specifies a range. This is of the form <start>,<end>
and, because there's nothing before the comma, it assumes the current line (the one where you found the blank line) is the start.
,/。/ -指定一个范围。这是
After the comma is /./-
which means search for the next character (.
means any character) then back up one line (/./-
is short for /./-1
since the one is implied if no value is given). You'll find that pattern .
on the first non-blank line following the one you're operating on.
逗号后面是/。/-这意味着搜索下一个字符(。表示任何字符)然后备份一行(/。/- is short for /。/-1,因为如果没有给定的值,就暗示了这一点。你会发现这种模式。在第一个非空行跟踪您正在操作的一个。
In other words, the end of the range is the last blank line after or at the one you're currently operating on.
换句话说,这个范围的末尾是您当前操作的最后一个空行。
Then you execute a join over that range.
然后在该范围内执行联接。
If the start and the end of the range were equal (only one blank line was in the section), join does nothing. If they're not equal, join will join them all up.
如果这个范围的开始和结束是相等的(只有一个空行在这一节),join什么也不做。如果它们不相等,join会将它们全部连接起来。
That's the way in which it combines multiple blank lines into one.
这就是它将多个空行合并成一个的方法。
Lets look at an example (line numbers are not in the file):
让我们看一个例子(行号不在文件中):
1 Line 1
2
3 Line 3
4 Line 4
5
6
7
8
9 Line 9
The :g
command will find all blank lines and perform its operation on them (lines 2, 5, 6, 7 and 8).
g命令将找到所有的空行并对它们执行操作(第2、5、6、7和8行)。
For line 2, ,/./-j
will set up a range from 2 to 2 (next .
found on line 3 then subtract 1). A join on the range 2,2 does nothing.
第2行,,/。/-j将设置一个范围从2到2。在第3行找到,然后减去1)。
For line 5, ,/./-j
will set up a range from 5 to 8 (next .
found on line 9 then subtract 1). A join on the range 5,8 will join all those lines together.
第5行,,/。/-j将设置一个范围从5到8(下一个。在第9行找到,然后减去1)。
I'm not entirely certain about this but I think the operation may not be performed on lines that disappear as part of an earlier operation. That's because it would make no sense to process lines that have been deleted earlier in the cycle.
我并不完全确定这一点,但我认为这一操作可能不会在之前的操作中消失。这是因为对在循环中早期被删除的行进行处理是毫无意义的。
In other words, because lines 6 through 8 are deleted (combined with line 5), the global command doesn't operate on them after that. I base that on nothing more than the fact that the vim documentation states a two-pass algorithm, one to mark the lines, one to perform the operation.
换句话说,由于第6行到第8行被删除(与第5行合并),因此全局命令在此之后不会对它们进行操作。我的基础是vim文档说明了一个两遍算法,一个用来标记行,一个用于执行操作。
I may be wrong on that point (it wouldn't be the first time) but it's an implementation detail which doesn't affect the functionality.
在这一点上,我可能错了(这不是第一次),但它是一个实现细节,不会影响功能。