アクセスできるのは私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'
、すべての単語の定義が 1 行にまとめられます。この巨大なドキュメントでも、5 秒以内に完了します。
ほぼ望みどおりの結果が得られていますが、完璧ではありません。これを行うgrep -e '->word' ./dictionary.txt
と、単語の完全な定義が得られます。ただし、見た目は完璧ではありません。
出力に満足できない理由は、元の PDF がA4
ページに印刷されるようにフォーマットされていたため、長い単語があると切り詰められてしまうからです。次のようになります。
例えば
->word: This is a defini-
tion.
前のワークフローでファイルを処理すると、->word: This is a defini- tion.
目的の単語を grep したときに次の結果が得られました。
これまでに私が達成できたのは次のことです:
- 入力
->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
2 番目の手順を実行する前に、ダッシュと改行 ( ) を削除して、切り取られたすべての行を「結合」したいと思います。
そこで質問ですが、行末のダッシュ-
と改行文字\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 で抽出が完了した後に通常のテキストを grep すると得られる結果です (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 を実行すると次の結果が得られた時です。
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.
答え1
これは perl ではかなり簡単です。perl の-0
オプションは、入力レコードの区切り文字として改行ではなく NUL 文字を使用するように指示します。そのため、入力に NUL 文字がない限り、入力ファイル全体が 1 つのレコードとして扱われます。NUL 文字があっても、最初のレコードと同じように後続のレコードの処理が続けられます。
注: これは、入力ファイル全体がメモリに収まる必要があることを意味します。16 GB 以上の RAM を搭載した最新のシステムでは、これが問題になる可能性は低いです。RAM が不十分だがスワップが十分にある古いシステムでは、それでも動作しますが、速度は大幅に低下します。
$ cat input.txt
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
$ perl -0 -p -e 's/-\s*\n//g' input.txt
->firstword: This is a definition.
->secondword: This is a second definition.
これにより、ハイフンの後に 0 個以上の空白文字 ( \s
、下記参照) が続き、その後に改行文字 ( \n
) が続くすべてのシーケンスが削除されます。
\s*
正規表現の部分は、末尾の空白文字に一致させるためにあります。かもしれない行末に空白文字を置く - 私の経験では、テキスト行の末尾に空白文字があるのはよくあることです(そして、空白文字は印刷されない文字、つまり見えない文字なので見つけにくいです)。代わりに、*
(0個以上の空間文字) または[ \t]*
(0 個以上のスペースまたはタブ) または\h*
(0 個以上の水平の代わりに空白文字を使用します\s*
。
からman perlre
:
空白とみなされる文字セットは、Unicode が「パターン空白」と呼ぶものです。具体的には次の通りです。
U+0009 CHARACTER TABULATION U+000A LINE FEED U+000B LINE TABULATION U+000C FORM FEED U+000D CARRIAGE RETURN U+0020 SPACE U+0085 NEXT LINE U+200E LEFT-TO-RIGHT MARK U+200F RIGHT-TO-LEFT MARK U+2028 LINE SEPARATOR U+2029 PARAGRAPH SEPARATOR
ノート:
- 文字
-
は、使用される可能性のある唯一の「ハイフン」または「ダッシュ」文字ではありません。Wikipediaには、Unicodeをリストしたページがあります。ハイフンそしてダッシュ文字です。幸い、Perl には優れた Unicode 処理機能があるため、このワンライナーを書き直すと、 の代わりに\p{Dash}
(または) を使用して、ダッシュ カテゴリの文字すべてに一致させることができます。\p{Pd}
-
$ perl -0 -p -e 's/\p{Dash}\h*\n//g' input.txt
->firstword: This is a definition.
->secondword: This is a second definition.
ただし、この方法では、em ダッシュはハイフンと同じように扱われます (つまり、ハイフンと同様に行末の em ダッシュが削除されます)。また、括弧の代わりに em ダッシュを使用することは珍しくありません。 「ハイフン」が非推奨であるという警告メッセージが表示されてもかまわない場合は\p{Hyphen}
、代わりにを使用\p{Dash}
できます。または、ハイフンとして扱いたい Unicode コード ポイントのみを含む括弧式を使用することもできます - 例:
perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g' input.txt
各単語の定義を で始めないことをお勧めします
->
。そうすると、grep で単語を検索するときに不必要に扱いにくくなります。検索文字列は引用符で囲む必要があり (>
シェルがリダイレクトに使用する のため)、先頭に を付ける必要があります--
( のため-
。そうしないと、grep は検索パターンをオプションとして処理します)。たとえば、次のようには実行できません。grep ^firstword: dictionary.txt
代わりに、次の操作を行う必要があります。
grep -- '^->firstword:' dictionary.txt
より良い例として、画像からテキストを抽出しました。テッセラクトOCRこれを、次のコードが続かない改行もすべて削除するバージョンの Perl ワンライナーで実行します->
。
$ cat input2.txt
->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
adjudicacion de bienes de quien muere sin testar.
Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesis
abidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Parana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 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 mas alla del talud continental, y corresponden a
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g; s/\n+(?!->)//g' input2.txt
->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 yadjudicacion de bienes de quien muere sin testar.Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos partiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesisabidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca delParana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familiaguaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice delas zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a
最終的な出力ファイルからシーケンスを削除することをお勧めします->
。これはテキストの処理中は便利なマーカーですが、その後は問題になります。
@zevzek からのコメントは、「大量の RAM を使用する」問題を解決します。入力レコードの区切り文字として NUL を使用する代わりに、->
区切り文字として使用します。これにより、Perl スクリプトは一度にファイル全体ではなく、一度に 1 つの単語定義のみを読み取ります。これにより、使用可能なすべての RAM が使用されなくなり、システムのスワップが発生しなくなるため、非常に大きな入力ファイルでも実行速度が大幅に向上します。
スクリプトには他にも変更が必要です。これは、始まり新しい単語の定義として終わり以前の定義の。具体的には、次のことが必要です。
- コマンドライン オプション
-p
(常に現在のレコードを出力する) を-n
(指示された場合にのみ現在のレコードを出力する) に変更します。 - 行末文字を削除します(perl の
chomp()
関数がこれを実行します) - 入力レコードが空か空白のみかを確認してください。想像上の最初の実際のレコード「abigeato」の前に空のレコードがあり、それを印刷したくありません。(なぜ突然、架空の空のレコードが現れるのでしょうか?
->
これは、新しいレコードの始まりではなく、レコードの終わりを示しているためです。in は、->
前->abigeato
の (空の) レコードと新しい「abigeato」レコードの間の区切りです) - 変更されたレコードを「->」と改行で出力します。
これらをすべて合わせると、最終的なワンライナーは次のようになります。
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
s/\n+(?!->)//g' input2.txt
これに:
perl -n -e 'BEGIN { $/="->" };
chomp;
next if m/^\s*$/;
s/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
s/\n+//g;
print "->$_\n"' input2.txt
このバージョンの出力は、最終出力行が必ず改行 ( ) で終わることを除いて、オリジナルと同じです\n
。オリジナルではこれが保証されておらず、実際には が続かない改行をすべて削除することでこれを防いでいました->
。これは無料のボーナスです。なぜなら、技術的には、すべての行が ... で終わる場合にのみ、Unix のファイルはテキスト ファイルとなるからです\n
。ほとんどの場合、これは問題になりません (少なくとも、標準のテキスト処理ツールの最新バージョンでは問題になりません)。ただし、一部のプログラムでは、 で終わらない場合、「テキスト ファイル」の最終行を正しく処理しません\n
。
(ちなみに、元のコードは、END ブロックを追加して出力の最後に改行を追加することで修正できます。END { print "\n" }
)
$/
は、入力レコード区切り文字を定義する perl 変数です ( man perlvar
perl の定義済み/特殊/制御変数の詳細については を参照してください)。これは、RS
の 変数に似ていますawk
。以前は、perl のオプションを使用して-0
これを NUL 文字に設定していました ( man perlrun
perl のコマンドライン オプションの詳細については を参照してください)。
BEGIN
ステートメントは、スクリプトの先頭、つまりwhile(<>) { ..... }
Perl の-p
またはオプション (これにより、Perl はそれぞれスーパーパワーのまたは の-n
ように動作します) を使用することによって発生する暗黙のループの前と外側で 1 回発生します。同様に、ステートメントは、すべての入力が読み取られて処理された後、スクリプトの最後に 1 回発生します。sed
sed -n
END
答え2
次のパターンを使用して単一のスクリプトで実行することをお勧めしますN;P;D
。
sed -e ':loop' -e '$!N;/\n->/!s/-*\n/ /;tloop' -e 'P;D'
s/-*\n/ /
新しい行が で始まるまで、'N'next 行を追加し、オプションのダッシュ ( ) を使用して改行を削除するループを実行します->
。