Vim - 对文件中的每一行数字进行排序?

时间:2014-09-16 13:54:10

标签: regex vim

我有一个如下文件:

Pallets
24 1 345 232 345 1 432 45 0 3

some text
more text

COPIES
542 11,456 1,576 1,212 13,229 46,035 9,061 10,642 13,044
CHARGES
225.45 4,464.90 613.91 511.73 5,140.22 17,532.10 3,473.52 4,059.68 5,064.39

是否可以对作为数字列表的每一行进行排序?

就像(我想象的):

如果匹配pattern / ^ \ d + /然后对该行进行排序。

这可能吗?

编辑。这是输出。

Pallets
0 1 1 232 24 3 345 345 432 45 

some text
more text

COPIES
542 1,212 1,576 9,061 10,642 11,456 13,044 13,229 46,035 
CHARGES
225.45 511.73 613.91 3,473.52 4,059.68 4,464.90 5,064.39 5,140.22 17,532.10 

编辑。这是我到目前为止所做的(忽略逗号和小数部分)

%s/\n\(\d.*\)\n/\rSTART\r\1\rEND\r/
g/^\d/ s/ /\r/g
#Throwing away decimal for now..
g/^\d/ s/,\|\.\d\+//
g/START/+,/END/- sort
g/START/+,/END/- s/\n/ /
%s/ END$//
g/^START/d

2 个答案:

答案 0 :(得分:4)

您可以先将记录拆分为单独的行,对它们进行排序,然后重新加入:

:s/ /\r/g
:'[,']sort
:'[,']join

如果您不使用空格作为分隔符,则必须使用:s重新加入:

:'[,']s/\n/,/

'[,']可以方便地选择修改后的范围(从行的初始分割开始),因此您无需使用行号或人工引入BEGIN..END保护。

答案 1 :(得分:1)

我想我会从全局:g命令中使用setline(),split()和sort()。

这比初看起来更难,因为我们需要将数字转换为浮点数,而且我们还需要删除逗号:

g#^\d\+#call setline('.', join(sort(map(split(getline('.')), "str2float(substitute(v:val, ',', '', 'g'))"), 'n')))
  • getline()获取当前行的内容
  • split()在字符串列表中自行获取每个数字
  • map()将操作应用于列表中的每个字符串
    • substitute()剥离逗号
    • str2float()将其转换为数字
  • sort()对数字列表进行排序
  • join()是将列表重新加入一个字符串
  • setline()将替换行内容

编辑:这依赖于sort()函数的'n'标志,该标志在7.4.341中添加,以允许对数字进行排序,而不是始终将它们视为字符串。在旧版本的Vim中,您仍然可以使用此解决方案,而不是“n”传递可以比较项目的函数名称。有关如何创建此类函数的详细信息,请参阅:help sort()和示例。注意,使用这种方式的函数,也可以让你保持逗号格式等,而上面给出的直接解决方案删除了​​逗号,即使原始行只有一个整数,也总是加一个小数。

替代方法:如果您不喜欢使用set / getline函数,您也可以在一个替换命令中执行整个操作,该命令以相同的方式执行匹配整行的替换一个数字:

:%s/^\d\+.*/\=join(sort(map(split(submatch(0)), "str2float(substitute(v:val, ',', '', 'g'))"), 'n'))/e

这以相同的方式工作,但使用submatch(0)而不是getline('.'),并依赖于\=项的表达式替换。有关详细信息,请参阅:help submatch():help sub-replace-expression。我怀疑存在明显的速度差异,因此您使用的方法更多是个人偏好。