有什么区别:g和:vs中的%s命令

时间:2014-09-05 11:09:54

标签: vim

今天我开始使用vim。我对:g:%s命令感到困惑。那么,:g:%s命令之间的区别是什么?

3 个答案:

答案 0 :(得分:35)

:gglobal的缩写,在与正则表达式匹配的所有行上执行命令:

:g/LinesThatMatchThisRegex/ExecuteThisCommand

示例:

:g/hello/d

这将删除(d)包含hello的所有行。

另一方面,:%s只执行搜索(在正则表达式上)并替换整个文件:

:%s/hello/world/g

最后的g表示globalgreedy(这是有争议的),因此它将替换该行上的所有匹配项,而不是每行一个。如果您想手动确认每次更换,也可以使用c标记(:%s/hello/world/gc)。

此命令将所有hello替换为world

:g:%s命令都支持正则表达式。

s命令表示substitute%表示整个缓冲区。所以%s意味着在整个缓冲区中替代。您还可以给出一个行范围:

:10,15s/hello/world/g

这将执行之前在第10行到第15行(包括第10行)中看到的搜索和替换。

答案 1 :(得分:8)

他们是不同的。

:g可以为匹配的行执行命令:s是其中一个命令。那就是你可以组合:g and s

:%s只需对整个缓冲区进行搜索和替换,即使它也可以使用表达式执行其他操作,但它不像:g那么简单。

E.g:

:g/foo/s/bar/blah/g   

这将在包含bar->blah的行上进行foo替换。使用:s,我们可以:

:%s/foo/\=substitute(getline('.'), 'bar','blah','g')

所以:g更容易。

因此,如果您正在处理替换任务,通常应首先提出:s。如果你想为所有与xxx匹配的行做,我想删除/ join / indent /....... :g对你有帮助。

答案 2 :(得分:3)

评论:

vi或vim中的“:”模式(例如ex-mode)命令具有以下形式:

[Address-specifier] [command] [command-specifics] [cmd-modifiers]

地址可以是单个行地址(ex-mode在“行”上运行)或行范围。

例如,“ p”中的一个非常简单的命令将打印出所寻址的行。

:1p    - will print line 1.
:5p    - will print line 5.
:1,5p  - will print lines 1 through 5.  1,5 is an address range.
:7,+3p  - will print lines 7 through 10 (7,7+3=10).  A relative range.

地址空间中有一些简写形式。 $和%最受欢迎。

$ means "last line in the file".   Thus the expression:
1,$p   - will print all lines, 1 to the LAST-line in the file.

表达式1,$如此频繁地使用(例如,将以下命令应用于文件中的所有行),以致其缩写甚至更短一些。 %表示“ 1,$” 所以:

%p  - will print all lines, 1 to the LAST-line in the file, just like 1,$

还有一个特殊的“全局”命令,其效果将提供一组地址前缀,该地址不一定是线性范围的行,而是由正则表达式匹配确定。 “:g / regex /”前缀适合前命令格式的“地址说明符”部分(而不是其后的命令部分)。 它允许指定行的“列表”,由正则表达式匹配,而不是“行号”或“行范围”。该匹配通过该行中显示的正则表达式来应用,然后将该行包括在该命令将应用到的行列表中。

:1,$ s vs%s vs:g /./ s的应用

以以下文件为例:

1: 1
2: 1 2 3 4 5 6 1 2
3: 3 2 1
4: 2 3 1 2

此命令,使用全局前缀/正则表达式作为地址,并使用“ p”打印命令:

:g/1 2/p   - will print
2: 1 2 3 4 5 6 1 2
4: 2 3 1 2

第2行和第4行均与:g / 1 2 /正则表达式匹配,并有效地扩展为行号列表,并对列表中的每个项目应用以下命令。大致类似于此命令)。 :2p 4p

替换命令允许用其他文本替换与正则表达式匹配的字段。如果将替换命令应用于示例文件,则在第2行,我们可以看到其效果。

1: ....
2: 1 2 3 4 5 6 1 2
3: ....

命令:

:2s/1 2/2 1/   will change line 2 to be instead:  2: 2 1 3 4 5 6 1 2

仅将模式“ 1 2”的第一个实例更改为“ 2 1”。 如果我们使用“ u”“撤消”该命令,则可以再次运行该命令,并对其进行修改。 我们可以在命令上使用“ p”修饰符,对于“替代”并没有太大作用。 它会应用更改,但还会在屏幕底部显示已应用的更改(在此示例中有些多余)。

:2s/1 2/2 1/p
u (to undo), and then we try it again.

我们可以使用“ c”修饰符进行确认。

:2s/1 2/2 1/c   The "confirm" modifier for the substitute asks for confirmation on each change.

u(撤消)。

“全局”修饰符。 (不是全局地址/正则表达式地址运算符)可以使replace命令在一行上执行多次替换。

:2s/1 2/2 1/g    - The "g" here is a modifier to the "s" substitute command.

这意味着在THE LINE上进行全局替换。修饰符修改“命令”,并且命令应用于设置地址字段的1行或多行。应用于替代命令末尾的“ g”表示:在此行上进行全局替代,例如每次替换命令的正则表达式出现时,都要执行替换。

2: 2 1 3 4 5 6 2 1     - Here, both the first and second instance are substituted.

如果替代命令找不到匹配的正则表达式,则它什么都不做。这意味着它可以应用于一系列行,并且仅对至少与替代命令regex匹配的行有影响。

1,4 s/1 2/2 1/
1,$ s/1 2/2 1/
%s/1 2/2 1/

都是等效的,并将替换第一次出现的 替换命令regex匹配模式,以及替换模式。

1: 1
2: 1 2 3 4 5 6 1 2
3: 3 2 1
4: 2 3 1 2

成为:

1: 1
2: 2 1 3 4 5 6 1 2
3: 3 2 1
4: 2 3 2 1

在末尾加上“ g”可得出:

 :%s/1 2/2 1/g
1: 1
2: 2 1 3 4 5 6 2 1
3: 3 2 1
4: 2 3 2 1

g:/ regex前缀

:g / regex /地址说明符适用于其后的所有命令,并且该命令可以包括替代命令,包括“ g”修饰符。

:g/3 4/s/1 2/2 1/g

此命令说,“使用regex / 3 4 /全局匹配行”,然后运行命令

:s/1 2/2 1/g.    

仅第2行包含正则表达式/ 3 4 /,因此仅匹配第2行。因此在此文件上:

:g/3 4/s/1 2/2 1/g is equivalent to:
:2s/1 2/3 4/g, which substitutes all occurrences of 1 2 with 2 1.

1: 1
2: 1 2 3 4 5 6 1 2
3: 3 2 1
4: 2 3 1 2

成为:

1: 1
2: 2 1 3 4 5 6 2 1
3: 3 2 1
4: 2 3 1 2

注意第4行:不变,因为它没有与地址说明符行匹配的模式“ 3 4”。

:g/regex-line-match/s/match-regex-substitute/sub-pattern/g 

:%s/match-regex-substitute/sub-pattern/g

中,通常两行 是等效的。它们通常是等效的。等价取决于正则表达式模式及其匹配,并且因为当一行没有匹配的match-regex-substitute匹配模式时,“替代”什么也没做。

% = 1,$ which matches all lines, and then applies the substitute pattern.
:g/./   would match every line, if prefixed.

“ global / regex”前缀的正则表达式模式(如果与替代项的match-pattern相同)会带来很多额外的输入,但会将替代命令限制为仅与global / regex匹配的行。如果global / regex表达式确实匹配每行,例如:g / ^。 $ /,则全局行将具有与%相同的效果。 (由于%将匹配所有行,并且:g/^。 $ /将匹配所有行,因此在基本情况下,“ s”将执行相同的操作。当使用更典型的正则表达式时(某些特定的字符串),则:g / regex /前缀将不同于%。命令“ s”仅适用于首先匹配g:/ refex /前缀的行,而不适用于所有行1 ,,。然后,替代者将尝试成功地(并替代)应用其自己的“每行”匹配模式,或者在给定的行中找不到匹配项,并且什么也不做。

global / regex前缀正则表达式与替换匹配regex模式不同时,global / regex前缀很有趣。在这种情况下,您首先应用global / regex FIRST(以确定随后要使用的行),即使用替代命令中的替代“ match-replace-regex”模式(可以不同)。如上面的示例所示,在第二个示例中,我们使用了全局/正则表达式前缀“ 3 4”和替代匹配正则表达式模式“ 1 2”。

非常高级:

虽然global / regex本质上构建了要在其上应用命令的行的列表,但是该列表的构建方式与1 ,, $或其他固定范围说明符不同。在输入:[address]命令时,“一次全部”计算固定的说明符。另一方面,global / regex命令将在其下级命令的每个单独应用程序之后重新计算其行目标。

我们将使用“ join”命令来说明区别。

1: 1
2: 1 2 3 4 5 6 1 2
3: 3 2 1
4: 2 3 1 2

如果我指定了一定范围的命令来应用“ join”命令,则使用范围语法,例如::1,$ j(或:%j)将呈现:

1: 1 1 2 3 4 5 6 1 2 3 2 1 2 3 1 2

之所以会发生这种情况,是因为1,$首先选择了1,4行,然后将“ j”应用于所选的每一行,将范围的所有行组合在一起。)

但是如果我们改为使用全局前缀运算符(匹配所有行),则应用程序将有所不同:

:g/./j

这将呈现:

 1: 1 1 2 3 4 5 6 1 2
 2: 3 2 1 2 3 1 2

之所以会出现差异,是因为在两种语法的每一种中都应用了命令的“方式”和“时间”。在第一种:%j语法中,所有行都是预先计算的,然后将“ j”应用于每行。

使用global / regex语法时,在每次应用命令后,将按“随行即用”和“从您所在的位置”应用行和命令。因此:g /./ j命令将首先匹配LINE1,然后运行“ j”,将行1 + 2 = new-1组合在一起。然后,它前进到文件中的“下一个”行(新文件​​new-2),与该行匹配(/./匹配所有),并将“ j”应用于new-2(原始行3)和new-3 (原始4)创建new-new-2 = 3 + 4。然后前进到“新文件”中的下一行,即第3行(但由于没有new-new-3,因此它停止了。)结果是:

 1: 1 1 2 3 4 5 6 1 2
 2: 3 2 1 2 3 1 2

主要区别在于,在应用命令实例之后,全局正则表达式搜索将在应用命令后存在的文件的“下一个”行上恢复。

如前所述,海报的总字数要少得多(但假定读者掌握了更多的知识):

:g/first-search-pattern/s/match-pattern/substitute-pattern/g  or /gc for confirm.

摘要:

所有这些模式都可以不同,尾随的g或gc可以存在(每行中的所有事件,有或没有确认),也可以省略(仅在每行中的第一次出现)。撰写时:

:%s/pattern/replace/g    is common, the following is nearly equivalent:
:g/./s/pattern/replace/g  (less common, but basically the with "substitute" command).