将文本文件限制为一定的字长,但保留完整的句子

limit text files to a certain word length, but keep complete sentences

我有一个文本文件语料库需要复制,但将每个文件限制为大致相同的字长,同时保持完整的句子。将 {.?!} 内的任何标点符号视为句子边界是可以接受的。我可以用 python 做到这一点,但我正在努力学习 bash,所以欢迎提出建议。我一直在考虑的方法是将我的目标字长超出几个字,然后 trim 结果到最后一句边界。

我熟悉 headwc,但我想不出将两者结合起来的方法。 headman 文件未指明使用字数统计的方法,wcman 文件未指明拆分文件的方法。

上下文: 我正在使用机器学习进行文本分类任务(使用 weka 作为记录)。我想确保文本长度(在我的数据中变化很大)不会对结果产生太大影响。为此,我尝试在执行特征提取之前标准化我的文本长度。

让我们考虑这个测试文件:

$ cat file
Do I exist? I program. Therefore, I am!

假设我们要运行整理此文件以完成不超过 20 个字符的句子:

$ awk -v n=20 -v RS='[.?!]' '{if (length(s [=11=] RT)>n) exit; else s=s [=11=] RT;} END{print s;}' file
Do I exist?

如果我们想要 30 个字符或更少:

$ awk -v n=30 -v RS='[.?!]' '{if (length(s [=12=] RT)>n) exit; else s=s [=12=] RT;} END{print s;}' file
Do I exist? I program.

工作原理

  • -v n=20

    这会将 awk 变量 n 设置为我们想要的最大长度(不包括文件的最后换行符)。

  • -v RS='[.?!]'

    这会将 awk 记录分隔符 RS 设置为您提到的三个字符中的任何一个。

  • if (length(s [=19=] RT)>n) exit; else s=s [=19=] RT

    对于文件中的每条记录(一条记录是一个句子),我们测试将其添加到 s 是否会使输出太长。如果它使输出太长,那么我们就退出。如果没有,我们将其添加到 s.

    在awk中,[=22=]表示完整的记录,RT是awk在记录末尾找到的记录分隔符。

  • END{print s;}

    在我们退出之前,这将打印字符串 s.

备选方案 1:T运行根据字数分类

假设我们想要运行根据字数进行分类。如果我们想要,例如,6个字:

$ awk -v n=6 -v RS='[[:space:]]+' 'NR>n{exit;} {printf "%s%s",[=13=],RT;} END{print"";}' file
Do I exist? I program. Therefore, 

区别在于我们知道使用空格作为记录分隔符。这样,每条记录就是一个字,一直打印字,直到达到极限。

备选方案 2:完整句子但字数有限

$ awk -v n=6 -v RS='[.?!]' '{c+=NF; if (c>n) exit; else s=s [=14=] RT;} END{print s;}' file
Do I exist? I program.

Mac OSX

以上将记录分隔符 RS 设置为正则表达式。这可能需要 GNU awk (gawk)。 OSX man page for awk 没有说明是否支持此功能。然而,@bebop 报告说,在从 macports 安装 gawk 后,上述代码可以 运行 在 OSX 上成功。