我有一个我需要复制的文本文件集,但是在保持完整句子的同时将每个文件限制为大致相同的单词长度。将{.?!}
内的任何标点符号视为句子边界是可以接受的。我可以用python做到这一点,但我正在尝试学习bash,所以欢迎提出建议。我一直在考虑的方法是将目标字长超过几个字,然后将结果修剪到最后一个句子边界。
我熟悉head
和wc
,但我无法想出将两者结合起来的方法。 man
的{{1}}文件未指明使用字数的方法,head
的{{1}}文件未指明分割文件的方法。
上下文:
我正在开发一个带有机器学习的文本分类任务(使用man
作为记录)。我想确保文本长度(在我的数据中变化很大)不会过多地影响结果。为此,我尝试在执行特征提取之前规范化文本长度。
答案 0 :(得分:2)
让我们考虑一下这个测试文件:
$ cat file
Do I exist? I program. Therefore, I am!
假设我们要截断此文件以完成20个字符或更少的句子:
$ awk -v n=20 -v RS='[.?!]' '{if (length(s $0 RT)>n) exit; else s=s $0 RT;} END{print s;}' file
Do I exist?
如果我们想要30个字符或更少:
$ awk -v n=30 -v RS='[.?!]' '{if (length(s $0 RT)>n) exit; else s=s $0 RT;} END{print s;}' file
Do I exist? I program.
-v n=20
这会将awk变量n
设置为我们想要的最大长度(不包括文件的最终换行符)。
-v RS='[.?!]'
这会将awk记录分隔符RS
设置为您提到的三个字符中的任何一个。
if (length(s $0 RT)>n) exit; else s=s $0 RT
对于文件中的每条记录(记录是句子),我们测试是否将其添加到s
会使输出太长。如果它使输出太长,那么我们退出。如果没有,我们会将其添加到s
。
在awk中,$0
表示完整记录,RT
是awk在记录末尾找到的记录分隔符。
END{print s;}
在退出之前,会打印字符串s
。
假设我们想要根据单词的数量进行截断。如果我们想要,例如,6个字:
$ awk -v n=6 -v RS='[[:space:]]+' 'NR>n{exit;} {printf "%s%s",$0,RT;} END{print"";}' file
Do I exist? I program. Therefore,
不同之处在于我们知道使用空格作为记录分隔符。通过这种方式,每个记录都是一个单词并保持打印单词,直到达到极限。
$ awk -v n=6 -v RS='[.?!]' '{c+=NF; if (c>n) exit; else s=s $0 RT;} END{print s;}' file
Do I exist? I program.
上面将记录分隔符RS
设置为正则表达式。这可能需要GNU awk(gawk)。 OSX man page for awk
未说明是否支持此功能。但是,@ bebop报告说,从macports安装gawk
后,上述代码可以在OSX上成功运行。