希望将内容行分开,保留一个标题。
我做了大量的文本处理,我喜欢使用unix一行程序,因为随着时间的推移,它们对我来说很容易组织(相对于大量的脚本),我可以很容易地把它们链接在一起,我喜欢(重新)学习如何使用经典的unix函数。通常我会使用一个简短的awk,perl,或ruby一行程序,这取决于哪个是最优雅的。
这里我有X行逗号分隔的项目。我想把这些分开,保留标题。
输入:
animals = lizard, bird, bee, snake, whale, eagle, beetle, mule, hare, goose, horse, mouse, pig, dog, frog, bug, fish, duck, camel, squirrel, owl, chicken, pigeon, lion, sheep, bear, spider, deer, tiger, lobster, dinosaur, cat, goat, rat, cricket, rabbit, elephant, crow, fox, donkey, monkey, butterfly, crab, leopard, moth, shark, salmon, shrimp, mosquito, horseshoe crab
输出:
animals = lizard, bird, bee, snake, whale, eagle, beetle, mule, hare
animals = goose, horse, mouse, pig, dog, frog, bug, fish, duck
animals = camel, squirrel, owl, chicken, pigeon, lion, sheep, bear, spider
animals = deer, tiger, lobster, dinosaur, cat, goat, rat, cricket, rabbit
animals = elephant, crow, fox, donkey, monkey, butterfly, crab, leopard, moth
animals = shark, salmon, shrimp, mosquito, horseshoe crab
算法详细信息:
- 输入行由标题词、等号和逗号分隔的至少1个项目的列表组成。
- 在本例中,大多数单词都是单个单词,但单词可以包含空格(例如,结尾处的“horseshoe crab”)
- 分割为9个项目,除非小于3个,在这种情况下,最终分割可能在一行上产生12个项目
- 有多条线。例如,下一条线可能是行星。
我有一个想法,先跳过空格,然后使用unix fold,再用awk把第一列拉下来。
echo "animals = lizard, bird, bee, snake, whale, eagle, beetle, mule, hare, goose, horse, mouse, pig, dog, frog, bug, fish, duck, camel, squirrel, owl, chicken, pigeon, lion, sheep, bear, spider, deer, tiger, lobster, dinosaur, cat, goat, rat, cricket, rabbit, elephant, crow, fox, donkey, monkey, butterfly, crab, leopard, moth, shark, salmon, shrimp, mosquito, horseshoe crab" \
| \tr ' ,' '_ ' \
| fold -s \
| perl -pe 's/=/\t/; s/^_/\t_/g;' \
| awk 'BEGIN{FS=OFS="\t"} $1==""{$1=p} {p=$1} 1' \
| tr '\t _' '=, '
但它只考虑字符长度(而不是项计数),没有考虑我的特殊情况,我不希望〈3个项挂在最后一行。
我觉得这是一个优雅的小拼图,有想法吗?
7条答案
按热度按时间dxxyhpgq1#
使用Perl,单向
或
显示在多行上以提高可读性,可以复制粘贴到bash终端中,但也可以在一行上输入。测试时添加了11(9+2)个项目。
备注
,
或=
首先提取中心词,然后提取行上的项9
)个元素,由,
连接的元素生成一个要打印的行,直到处理完所有元素。如果最后一组元素少于3个,则将其添加到上一个要打印的行eblbsuwk2#
您可以考虑以下
awk
:请特别注意此处使用的正则表达式
/([^,]+, ){1,9}(([^,]+, ){2}[^,]+$)?/
它匹配1到9个用
,
分隔符分隔的单词。这个正则表达式也有一个可选部分,匹配行尾之前最多3个单词。rqcrx0a63#
仅使用您展示的示例,请尝试以下
awk
程序。在GNUawk
中编写和测试,应该可以在任何awk
中工作。在这里我创建了一个名为
numberOfFields
的awk
变量,它包含了您要打印的字段的数量(按照所示的示例用新行分隔)。***OR***以上代码将
printf
语句分为两行(出于可读性目的),如果您希望将其本身分为一行,请尝试以下操作:***说明:***添加上述详细说明。
上述
printf
条件的说明:ecbunoof4#
一个
awk
创意:示例数据:
使用
-v min=3 -v max=9
,我们得到:解决OP关于使用一行程序的评论...
虽然这个
awk
脚本肯定可以塞进一个单行程序,我猜OP会a)发现它很难编辑/维护和b)太容易搞砸,如果不得不(重新)键入一遍又一遍。一个(显而易见的?)想法是将
awk
代码 Package 在函数中,例如:备注:
min
和max
值,以便从命令行提取$3
)或stdin(-
)提取的文件引用是否对文件独立调用:
或者在管道中调用:
两者均生成:
ggazkfy85#
svmlkihl6#
下面是两个处理一行代码的Ruby解决方案:变量
str
保存一行代码(示例中以'animals = ...'
开头的代码)。#1使用正则表达式
第一个
正则表达式可以用 * 自由间距模式 * 编写,使其具有自文档性。
Demo
当对示例
str
执行时,我们将发现以下内容。Ruby有一个惯例,就是在变量
_
的值没有被用于后续计算的情况下使用它,这主要是为了告诉读者。#2提取并分组单词
一个
通过部分解释,我们将获得该示例的以下内容:
由于
groups
的元素包含两个以上的元素(它包含五个),因此groups
不会被修改。如果最后一行被允许最多包含14个(而不是11个)元素,它将被更改为uyto3xhc7#
花了一些时间修改我的解决方案,通过在正则表达式链的末尾执行与
$1 = $1
等效的操作,使其在gawk
和mawk
上都能工作;$(NF!=NF=NF)
在内部扩展为NF != (NF=NF)
,它总是false,所以整个过程就是$0
,但是在其中嵌入$1=$1
: