vim:如何替换matchlist()中的子匹配?

时间:2014-10-22 10:46:30

标签: regex vim

有没有一种方法可以替换matchlist()中的子匹配并用它修改原始行?我喜欢编写一个脚本,用一步修改模式中的所有子匹配(可以是用户想要的任何内容)。

对于示例,原始行为some AfooBar,用户希望将其更改为some CfooDar

思考通用解决方案,适用于任何模式

let pattern = '\(A\)foo\(B\)'
let line    = 'some AfooBar'
let found   = matchlist( line, pattern )

found包含['AfooB', 'A', 'B', '', '', '', '', '', '', '']。现在我必须修改linesome CfooDar,所以最好的方法是通过修改其中的数字来重用matchlist()数组,然后“编译”该行:

let found[1] = 'C'
let found[3] = 'D'
let line     = MATCHLIST_TO_STRING( found )

据我所知,内置函数不可能,所以我需要写一个。在匹配之前不会修改该行的开头,因此我可以将该部分复制到'new_line':

let new_line = strpart( line, 0, match( line, pattern ) )

但在这一点上我不知道如何继续。我可以立即附加修改后的A,因为模式以它开头(在此示例中,但用户可以使用任何类型的模式)。但是我怎样才能找到fooB的(偏移)索引?在这个例子中,它很简单,因为行中没有其他fooB,但让我们看另一个例子:

let line    = 'A A A A A'
let pattern = 'A \(A\) A \(A\)'

如果我想将其修改为A B A C A,则很难检测到line中子匹配的位置。

一种解决方案是使用“内部单词”的子匹配(如上例中的foo),但它会减少有用的子匹配数。例如:

let pattern  = '\(A\)\(foo\)\(B\)'
let line     = 'some AfooBar'
let found    = matchlist( line, pattern )
" Remove the full match, we need only the submatches.
call remove( found, 0 )
let found[0] = 'C'
let found[2] = 'D'
let new_line = strpart( line, 0, match( line, pattern ) ) . join( found, '')

在这种情况下,我们使用了一个额外的子匹配,但A \(A\) A \(A\) A可能会变成\(A \)\(A\)\( A \)\(A\)\( A\)并且它太多了。

那么有没有一种方法可以在一个步骤中用新值替换所有子匹配?

1 个答案:

答案 0 :(得分:0)

整个问题都是XY的味道。那么询问您的初始问题而不是您的非工作解决方案呢?

简单:

call setline('.', substitute(getline('.'), 'A\(foo\)B', 'C\1D', 'g'))

更简单:

s/A\(foo\)B/c\1D/g