我busybox 1.27.2
只能访问。
我目前正在处理一本包含超过 50 万字和 6,000 多页的字典(从带有 ghostscript 的 PDF 中提取并转换为纯文本)。在一个20MB
.txt
文件中。最初,这本词典中的每个单词都有一个前导->
,以便于搜索单词。
我想要实现的是让它变得*nix
友好。这意味着如果我这样做:
grep -e '->myfancyword' ./dictionary.txt
.
结果我应该得到:
->fancyword: This is a very fancy word. *Definition going on for more than 6 lines*
这很容易通过去除所有换行符来完成,\n
因此每个单词都将在很长的一行中包含其所有定义,这没关系。我可以用所有替换\n
,tr -d '\n'
然后通过它的输出,sed 's/->/\n->/g'
所以我将在一行中得到所有单词的定义。即使在这个巨大的文档上,它也可以在不到 5 秒的时间内完成。
我几乎得到了我想要的结果,但并不完美。我可以做到这一点grep -e '->word' ./dictionary.txt
并得到这个词的完整定义。但它在外观上并不完美。
我对输出不满意的原因是因为原始 pdf 被格式化为打印在A4
页面上,这意味着当有一个长单词时,它被切掉了。像这样:
例如
->word: This is a defini-
tion.
如果我使用以前的工作流程处理文件,我得到:->word: This is a defini- tion.
当 grepping 所需的单词时。
到目前为止,我设法完成的是:
- 输入
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
应用
tr -d '\n' < ./dictionary.txt > ./dictionary2.txt
输出是:
->firstword: This is a defini- tion. ->secondword: This is a second defini- tion.
跑了:
sed -e 's/->/\n->/g' ./dictionary2.txt
结束于:
输出
->firstword: This is a defini- tion.
->secondword: This is a second defini- tion.
在进行第二步之前,我想删除破折号和换行符 ( -\n
) 以将所有切碎的线“连接”在一起。
所以,我的问题是:如何替换/删除行尾包含破折号-
和换行符\n
( -\n
) 的特定字符串?
我喜欢得到的是:
输出(请检查破折号和空格(-
)不再存在)
->firstword: This is a definition.
->secondword: This is a second definition.
谢谢你。
编辑:
这是PDF文件的页面:
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrón de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
adjudicación de bienes de quien muere sin testar.
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
->abiótico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. síntesis
abiótica
->abipón, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Paraná. U. t. c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurú hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, o en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
las zonas del mar profundo que se extienden más allá del talud continental, y corresponden a
profundidades mayores de 2000 m. 3. adj. Perteneciente o relativo a tales zonas.
->abiselar. 1. tr. biselar.
->abisinio, nia. 1. adj. Natural de Abisinia, hoy Etiopía. U. t. c. s. 2. adj. Perteneciente o re-
lativo a este país de África. 3. m. Lengua abisinia. V. rito abisinio
->abismado, da. (Del part. de abismar). 1. adj. Dicho de una persona, de su expresión, de
su gesto, etc.: Ensimismados, reconcentrados. 2. adj. Heráld. Dicho de una pieza del escudo:
Puesta en el abismo.
->abismal (1). (Del ár. hisp. almismár, y este del ár. clás. mismar). 1. m. Cada uno de los
clavos con que se fijaba en el asta el hierro de la lanza.abismal2. 1. adj. Perteneciente o re-
lativo al abismo. 2. adj. Muy profundo, insondable, incomprensible.
->abismar. 1. tr. Hundir en un abismo. U. t. c. prnl. 2. tr. Confundir, abatir. U. t. c. prnl. 3.
prnl. Entregarse del todo a la contemplación, al dolor, etc. 4. prnl. Am. sorprenderse (|| con-
moverse con algo imprevisto o raro).
->abismático, ca. 1. adj. abismal2.
->abismo. (Quizá del lat. vulg. *abyssimus, der. de abyssus, y este del gr. , sin fondo). 1.
m. Profundidad grande, imponente y peligrosa, como la de los mares, la de un tajo, la de una
sima, etc. U. t. en sent. fig. Se sumió en el abismo de la desesperación. 2. m. infierno (|| lugar
de castigo eterno). 3. m. Cosa inmensa, insondable o incomprensible. 4. m. Diferencia
grande entre cosas, personas, ideas, sentimientos, etc. 5. m. Heráld. Punto o parte central
del escudo. 6. m. Nic. Maldad, perdición, ruina moral.
这是在使用 ghostscript 完成提取后对常规文本进行 grepping 时得到的结果(仅使用 dos2unix 处理):
grep -e '->abiog' ./rae-dos2unix.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
这是在文本上完成前面的步骤(1-4)时,当我得到:
grep -e '->abiog' ./rae-una-linea.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par- tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
这在 perl 中相当容易。perl 的
-0
选项告诉它使用 NUL 字符而不是换行符作为输入记录分隔符,因此,除非输入中有 NUL 字符,否则它将把整个输入文件视为一条记录。即使有 NUL 字符,它也会继续处理后续记录,与第一个相同。注意:这确实意味着整个输入文件必须适合内存 - 在具有 16GB 或更多 RAM 的现代系统上,这不太可能成为问题。在 RAM 不足但交换空间足够的旧系统上,它仍然可以工作,但速度会慢得多。
这将删除每个连字符序列,后跟零个或多个空格字符(
\s
,见下文),后跟换行符(\n
)。\s*
正则表达式的一部分用于匹配可能位于行尾的尾随空白字符 - 根据我的经验,文本行带有尾随空格是很常见的(而且它们很难被发现,因为它们不是打印字符,即不可见)。或者,使用*
(零个或多个空格字符) 或[ \t]*
(零个或多个空格或制表符) 或\h*
(零个或多个水平空白字符) 而不是\s*
.来自
man perlre
:笔记:
-
字符并不是唯一可能使用的“连字符”或“破折号”字符。维基百科的页面列出了 unicode连字符和破折号字符。幸运的是,perl 具有良好的 unicode 处理能力,因此可以重写单行代码以使用\p{Dash}
(or\p{Pd}
) 而不是-
匹配所有破折号类别字符:但是,这会将 em-dashes 视为与连字符相同的处理(因此将删除行尾的 em-dash,与连字符相同)......并且使用 em-dashes 而不是括号并不少见. 如果您不介意有关“连字符”被弃用的警告消息,您可以使用
\p{Hyphen}
代替。\p{Dash}
或者,您可以使用仅包含要视为连字符的 unicode 代码点的括号表达式 - 例如我建议不要让每个单词定义都以
->
. 这将使使用 grep 搜索单词变得不必要的尴尬 - 搜索字符串必须被引用(因为>
shell 用于重定向的 )并在前面--
(因为-
,否则 grep 会将您的搜索模式视为如果您的意思是它们是选项)。例如,您将无法做到:相反,您必须这样做:
举个更好的例子,我使用tesseract-ocr从您的图像中提取了文本,并通过 perl one-liner 版本运行它,该版本还删除了所有不跟在后面的换行符
->
:我仍然建议
->
从最终输出文件中删除该序列。在处理文本时它是一个有用的标记,但之后会出现问题。@zevzek 的评论解决了“使用大量 RAM”的问题。不使用 NUL 作为输入记录分隔符,而是使用
->
分隔符。这使得 perl 脚本一次只能读取一个单词定义,而不是一次读取整个文件。这将使它在输入文件非常大的情况下运行得更快,因为它不会使用所有可用的 RAM 并导致系统交换。需要对脚本进行其他更改,因为我们现在将标记新单词定义开头的字符序列视为先前定义的结尾。具体来说,我们现在需要:
-p
(始终输出当前记录)更改为-n
(仅在我们告诉它时输出当前记录)。chomp()
函数就是这样做的)->
now 表示记录的结束,而不是新记录的开始。in 是上一个(空)记录和新的“abigeato”记录之间的分隔符->
)->abigeato
总之,这些将改变最终的单线:
对此:
此版本的输出与原始版本相同,只是最终输出行保证以换行符 (
\n
) 结束。原版并没有保证这一点,实际上它通过删除所有没有跟随的换行符来阻止它->
。这是一个免费的奖励,因为从技术上讲,如果每一行都以\n
.... 结尾,则文件只是 unix 中的文本文件。大多数情况下,这无关紧要(至少,对于标准文本处理工具的现代版本而言) ,但如果“文本文件”的最后一行不以 . 结尾,则某些程序无法正确处理它\n
。(顺便说一句,可以通过添加一个 END 块将换行符添加回输出的末尾来修复原始内容
END { print "\n" }
:)$/
是一个定义输入记录分隔符的 perl 变量(有关 perl 的预定义/特殊/控制变量的详细信息,请参阅man perlvar
),类似于. 以前,我使用 perl 的选项将其设置为 NUL 字符(有关 perl 的命令行选项的详细信息,请参阅)。RS
awk
-0
man perlrun
BEGIN
语句在脚本的开头发生一次,在while(<>) { ..... }
使用 perl-p
或-n
选项引起的隐式循环之前和之外(这使得 perl 的行为有点像超级动力sed
或sed -n
分别)。类似地,END
在所有输入都被读取和处理之后,一个语句在脚本结束时发生一次。N;P;D
我建议使用以下模式在单个脚本中执行此操作:您循环添加 'N'ext 行并使用可选的破折号 (
s/-*\n/ /
) 删除换行符,直到新行以 . 开头->
。