排序文件的一部分


8

是否可以在大文件中的两个字符串之间排序?

例如,当前文件为:

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

所需的输出为:

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

在这里,将分选HUT 03 VR控件HUT 04运动控件

在给定文件中,节标题以非空格字符开头,而节内容始终以空格或制表符开头。由于此文件有100多个节,因此在脚本/命令中硬编码节名称是不可行的


这些节是在固定行号上还是由模式定义的?
Sparhawk

节标题以行的第一个字符开头,而内容以空格/制表符开头。部分的编号不是固定的。
SHW

您只想对一个部分(根据问题和文本的标题)还是对每个部分进行排序?
库萨兰达

@Kusalananda我同意这一点上模棱两可;但是,示例输出确实显示了所有部分(或其部分)都已排序。
史蒂芬·基特

我不会说“ HUT”使用十六进制字符。
jlliagre

Answers:


7

在Python中:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

这将对所有部分(分别)进行排序,而不只是对两个特定行之间的部分进行排序。


高超!这是中风。
SHW

6

有趣的是,这是使用以下方法对单个部分进行排序的方法ex

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%

6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

这用于awk在与该行所在的节对应的每行前面添加一个数字(和制表符分隔符)。对于节标题,我们在其后添加一个数字,后跟一个退格字符(仅因为退格在制表符之前排序)。然后,我们在删除这些数字和添加的制表符分隔符之前,仅对这些数字上的结果数据进行排序。

通过在行的开头查找非空白字符来检测节标题。


1
真好!我特别喜欢退格键。
斯蒂芬·基特

1
使用这种方法,您还可以将节号(在HUT字段之后)用作前缀,也可以对节进行排序。
斯蒂芬·基特

3

您可以得到awksort进行合作以完成工作。

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • 用管道将每个内容行插入 sort
  • 调用closesort遇到部分标记时; 这导致sort将其输出刷新为标准输出并退出
  • 打印部分标记
  • sort节标记之后的内容行的新接管实例
  • 呼叫closesort末采取尾随内容的护理

1

对于这样的任务,我经常发现编写脚本很乏味。如果只需要执行一次(可能只需要处理几个文件),则在打开文件vim并键入以下命令后,可以使用宏很好地完成此操作:

  • GoFAKE SECTION<ESC>:在末尾添加一个伪造的部分,并确保这是在行的开头(您可能已经启用cindentautoindent启用了)。这也是对最后一部分进行排序所必需的。
  • gg:返回到文件的开头,然后文件从一个部分开始,向下一行 j
  • qq:开始录制宏以注册q
  • v:开始选择
  • /^\S\+<Enter>:搜索下一部分的开始
  • k:上一行
  • :!sort<Enter:对部分进行排序
  • nj:转到下一部分的第一个元素
  • q:停止录制宏
  • @q:重复宏
  • 100@@:重复宏几次(直到没有剩余的部分)
  • dd:删除文件的最后一行(FAKE SECTION

您可能要:set lazyredraw加快宏执行速度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.