列位置可视化逐行选择
Column position visual selection line by line
例子:
text téxt text |text| text
text text text |text| text
text téxt téxt |text| text
text téxt text |text| téxt
我正在选择一段文本“|text|”以上行数
我想知道的是每一行的startcolumn和endcolumn的列位置。
如果我使用:
echo col('"<') --> 17
echo col('">') --> 20
它给了我块第一行的开始列和块最后一行的结束列。
然而在每一行中我的块选择之前都有多字节字符。我想知道每一行的 col('"<') 和 col('">'):
17、20
16、19
18、21
17、20
如何获得这些?
我们从视觉(按块)选择的开始和结束列开始。这些是 屏幕列 ,即计算屏幕单元格。您想将它们转换为字节索引,对于每个覆盖的行。
因此,我们需要一种将屏幕列转换为字节索引的方法。如果我们使用游标,有一些方便的函数可以将它定位在特定的屏幕列上([N]|
命令),以及查询字节索引的函数(col()
)。因此,整个算法将通过 virtcol()
获得的选择开始和结束的屏幕列(分别标记为 '<
和 '>
)通过定位光标转换为字节索引.
这是一种实现方法:
:'<,'>global/^/
\ let positions = [] |
\ for mark in ['<', '>'] |
\ exe 'normal!' virtcol("'" . mark) . '|' |
\ call add(positions, col('.')) |
\ endfor |
\ echo positions
[17, 20]
[16, 19]
[18, 21]
[17, 20]
选择的开始和结束屏幕列可以通过virtcol()
获得。然后我们可以将光标定位到开始位置,然后定位到结束位置,通过col('.')
.
获取字节索引
为简单起见,我在这里使用 :global
遍历所有选定的行,并将列放入列表中。
作为 virtcol({mark})
returns 字符索引,您可以将其用作正则表达式中的计数器。
例如,我们有:
let first_col = virtcol("'<")
let last_col = virtcol("'>")
从这里开始,每行的3个部分可以用
得到
let lead = matchstr(getline(n), '\v^.{'.(first_col-1).'}')
let selection = matchstr(getline(n), '\v^.{'.(first_col-1).'}\zs.{'.(last_col-first_col+1).'}')
let tail = matchstr(getline(n), '\v^.{'.(last_col).'}\zs.*')
或者我们也可以使用matchlist()
let [all, lead, selection, tail; dummy] = matchlist(getline('.'), '\v^(.{'.(first_col-1).'})(.{'.(last_col-first_col+1).'})(.*)')
我想我们应该也可以使用 split()
,但它会很复杂。
请注意,由于这种手动计数,我们有了一个正则表达式,因此我们可以直接使用 :'<,'>substitute
。那样的话,直接用\%V
in the pattern. But beware, it's a little bit tricky to use correctly: to signal the end of the match, we need to negate the pattern. See this discussion on vi.SE来稍微解释一下就更简单了。
:'<,'>s/\v^(.{-})%V(.{-})%V@!(.*)/####/
或者,如果您希望在每个匹配项上应用函数,####
可以变为:\=(func1(submatch(1)).func2(submatch(2)).func3(submatch(3))
。这样,您可以保留 python 部分来实现各种 funcn()
功能。请注意,如果需要,您可以将多个参数传递给这些函数,甚至可以使用单个匹配项调用单个函数:\=singlefunc(submatch(1), submatch(2), submatch(3))
例子:
text téxt text |text| text
text text text |text| text
text téxt téxt |text| text
text téxt text |text| téxt
我正在选择一段文本“|text|”以上行数
我想知道的是每一行的startcolumn和endcolumn的列位置。
如果我使用:
echo col('"<') --> 17
echo col('">') --> 20
它给了我块第一行的开始列和块最后一行的结束列。
然而在每一行中我的块选择之前都有多字节字符。我想知道每一行的 col('"<') 和 col('">'):
17、20
16、19
18、21
17、20
如何获得这些?
我们从视觉(按块)选择的开始和结束列开始。这些是 屏幕列 ,即计算屏幕单元格。您想将它们转换为字节索引,对于每个覆盖的行。
因此,我们需要一种将屏幕列转换为字节索引的方法。如果我们使用游标,有一些方便的函数可以将它定位在特定的屏幕列上([N]|
命令),以及查询字节索引的函数(col()
)。因此,整个算法将通过 virtcol()
获得的选择开始和结束的屏幕列(分别标记为 '<
和 '>
)通过定位光标转换为字节索引.
这是一种实现方法:
:'<,'>global/^/
\ let positions = [] |
\ for mark in ['<', '>'] |
\ exe 'normal!' virtcol("'" . mark) . '|' |
\ call add(positions, col('.')) |
\ endfor |
\ echo positions
[17, 20]
[16, 19]
[18, 21]
[17, 20]
选择的开始和结束屏幕列可以通过virtcol()
获得。然后我们可以将光标定位到开始位置,然后定位到结束位置,通过col('.')
.
为简单起见,我在这里使用 :global
遍历所有选定的行,并将列放入列表中。
作为 virtcol({mark})
returns 字符索引,您可以将其用作正则表达式中的计数器。
例如,我们有:
let first_col = virtcol("'<")
let last_col = virtcol("'>")
从这里开始,每行的3个部分可以用
得到let lead = matchstr(getline(n), '\v^.{'.(first_col-1).'}')
let selection = matchstr(getline(n), '\v^.{'.(first_col-1).'}\zs.{'.(last_col-first_col+1).'}')
let tail = matchstr(getline(n), '\v^.{'.(last_col).'}\zs.*')
或者我们也可以使用matchlist()
let [all, lead, selection, tail; dummy] = matchlist(getline('.'), '\v^(.{'.(first_col-1).'})(.{'.(last_col-first_col+1).'})(.*)')
我想我们应该也可以使用 split()
,但它会很复杂。
请注意,由于这种手动计数,我们有了一个正则表达式,因此我们可以直接使用 :'<,'>substitute
。那样的话,直接用\%V
in the pattern. But beware, it's a little bit tricky to use correctly: to signal the end of the match, we need to negate the pattern. See this discussion on vi.SE来稍微解释一下就更简单了。
:'<,'>s/\v^(.{-})%V(.{-})%V@!(.*)/####/
或者,如果您希望在每个匹配项上应用函数,####
可以变为:\=(func1(submatch(1)).func2(submatch(2)).func3(submatch(3))
。这样,您可以保留 python 部分来实现各种 funcn()
功能。请注意,如果需要,您可以将多个参数传递给这些函数,甚至可以使用单个匹配项调用单个函数:\=singlefunc(submatch(1), submatch(2), submatch(3))