连续段落的分组排序(由空行分隔)?


8

我认为我现在在按排序方面很有经验;但是,到目前为止,我还没有找到如何对连续行进行排序的任何方法。

假设我们有一个文本文件,如下所示:(当然,非常简化)

Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

现在,是否可以对每个块分别按字母数字顺序对行进行排序?我的意思是说,结果是这样的:

Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

从我在sort手册页中找到的内容来看,使用内置的UNIX sort命令可能无法做到这一点。还是可以不必借助外部/第三方工具来完成?

Answers:


9

Drav的awk解决方案很好,但这意味着sort每段运行一个命令。为了避免这种情况,您可以执行以下操作:

< file awk -v n=0 '!NF{n++};{print n,$0}' | sort -k1n -k2 | cut -d' ' -f2-

或者,您可以在中完成整个操作perl

perl -ne 'if (/\S/){push@l,$_}else{print sort@l if@l;@l=();print}
          END{print sort @l if @l}' < file

请注意,在上面,分隔符是空行(对于awk一个行,只有空格或制表符的行,对于perl任何一个水平或垂直间隔字符的行),而不是空行。如果你想空行,你可以替换!NF使用!length$0=="",并/\S//./


还要感谢您,尤其是awk避免sort开销的解决方案!鬼!
语法错误

9
awk -v RS= -v cmd=sort '{print | cmd; close(cmd); print ""}' file

将记录分隔符设置为RS空字符串会使awk一步一次进入段落。对于每个段落,将段落(中的$0)用管道传输到cmd(设置为sort)并打印输出。打印出空白行以使用分隔输出段落print ""

如果我们提供perl示例,那么我将介绍一种替代Stephane方法的方法:

perl -e 'undef $/; print join "\n", sort (split /\n/), "\n" 
    foreach(split(/\n\n/, <>))' < file

取消设置字段分隔符(undef $/),这使我们可以使用<>和获取整个STDIN。然后split,我们围绕\n\n(段落)进行讨论。foreach“段落”,sort这些行通过split在换行符周围四处摇摆,sort然后将join它们重新排列在一起并附加在结尾处\n

但是,这样做的副作用是在最后一个段落上添加“尾随段落”分隔符(如果之前没有分隔符)。您可以使用稍微不那么漂亮的方法来解决此问题:

perl -e 'undef $/; print join "\n", sort (split /\n/) , (\$_ == \$list[-1] ? "" : "\n")
    foreach(@list = split(/\n\n/, <>))' < file

这会将段落分配给@list,然后进行“三元运算”以检查它是否是foreach\$_ == \$list[-1]检查)的最后一个元素。打印""如果是(? ...),其他(: ...)打印"\n"了所有其他的“段落”(元素@list)。


这很整齐!谢谢。您实际上是在调用/usr/bin/sort该行还是它是awk内置的“ sort”命令?
语法错误

调用sort命令,因此需要在每个循环上关闭(cmd):)
Drav Sloan

5

我在haskell中编写了一个工具,可让您在文本段落上使用sort,shuf,tac或任何其他命令。

https://gist.github.com/siers/01306a361c22f2de0122
编辑:此仓库中也包含该工具:https : //github.com/siers/haskell-import-sort

它将文本拆分为块,将子块与\0char 结合在一起,通过命令进行管道传输,最后反向执行相同的操作。

2015年8月28日:我发现此工具还有其他个人用途-在一行之后选择N个段落。

paramap grep -aA2 '^reddit usernames' < ~/my-username-file
reddit usernames

foo
bar
baz

a couple
more of these

4

如果您有可用的GNU awk,则可以使用内置asort()函数对每个块进行排序。像这样:

区块排序

function sort_n_print(array) {
  asort(array)
  for(i=1; i<=length(array); i++)
    print array[i]
  delete array
}

NF { a[++x] = $0 }

!NF { sort_n_print(a); print }

END { sort_n_print(a) }

像这样运行它:

awk -f blocksort.awk infile

1

TXR Lisp逐步:

$ cat data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(get-lines)' < data
("Echo" "Alpha" "Delta" "Charlie" "" "Golf" "Bravo" "Hotel" "Foxtrot")

$ txr -t '(get-lines)' < data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(partition* (get-lines) (op where [chain length zerop]))' < data
(("Echo" "Alpha" "Delta" "Charlie") ("Golf" "Bravo" "Hotel" "Foxtrot"))

$ txr -p '[mapcar sort (partition* (get-lines) (op where [chain length zerop]))]' < data
(("Alpha" "Charlie" "Delta" "Echo") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -p '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
(("Alpha" "Charlie" "Delta" "Echo") ("") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -t '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

参考:get-linespartition *opwherechainlengthzeropmapcarinterpose


请注意,在中,[mapcar sort ...]我们可以替换sort为通过外部过程通过管道传递字符串的函数。然后,我们可以得到一个用于在段落上分配文本处理外部命令的工具。
卡兹2015年
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.