私は検索が間違っているかもしれないと思いましたが、何の答えも見つかりませんでした。重複した内容がある場合はお知らせください。削除いたします。
問題の背景
私ack
(協会)、Perl 5を内部的に使用してnグラム、特に高次nグラムを得る。私が知っている構文(デフォルトでは最も多い$9
)を使用すると、最大9gまで取得できますが、10gは取得できません。使用するとサフィックスが$10
提供されます。そのようにして問題は解決されませんでした。はい$1
0
$(10)
${10}
いいえLanguage Modeling Toolkitを使用するソリューションに興味がありますack
。
私が使用したデータセットの1つはMark Twainの完全なコレクションでした。
(wget http://www.gutenberg.org/cache/epub/3200/pg3200.txt && mv pg3200.txt TWAIN_Mark_complete_orig.txt
)。
内容を分析しました(参照コメント分析ポストの最後に)解析結果をTWAIN_Mark_complete_parsed.txt
。
2グラムで得た結果は大丈夫です。コードと部分的な結果は次のとおりです。
time cat TWAIN_Mark_complete_parsed.txt | \
ack '(\S+) +(?=(\S+) +)' \
--output '$1 $2' | \
sort | uniq -c | \
sort -rn > Twain_2grams.txt
## `time` info not shown
$ head -n 2 Twain_2grams.txt
18176 of the
13288 in the
最大9gまで、
time cat TWAIN_Mark_complete_parsed.txt | \
ack '(\S+) (?=(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+))' \
--output '$1 $2 $3 $4 $5 $6 $7 $8 $9' | \
sort | uniq -c | sort -rn > Twain_9grams.txt
## time info not shown
$ head -n 2 Twain_9grams.txt
17 to mrs jane clemens and mrs moffett in st
17 mrs jane clemens and mrs moffett in st louis
ack
(各コマンドを入力するのではなく、コマンドをメタプログラミングしたことに注意してください。)
質問/私が試したこと
初めて10gを試したとき、結果は次のようになりました。
time cat TWAIN_Mark_complete_parsed.txt | \
ack '(\S+) (?=(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+))' \
--output '$1 $2 $3 $4 $5 $6 $7 $8 $9 $10' | \
sort | uniq -c | sort -rn > Twain_10grams.txt
$ head -n 2 Twain_10grams.txt
17 to mrs jane clemens and mrs moffett in st to0
17 mrs jane clemens and mrs moffett in st louis mrs0
何が起こっているのかをよりよく理解するために、
よりこの回答(そしてこのコメント)単語の違いを強調表示して色の違いを詳しく調べる方法を学びます。基本的にapt
まだyum
for colordiff
、そしてpip
for diff-highlight
。
$(10)
代わりに、$10
最初の2行の出力が提供されます。
17 to mrs jane clemens and mrs moffett in st $(10)
17 mrs jane clemens and mrs moffett in st louis $(10)
(2分後)。
${10}
代わりに、$10
最初の2行の出力が提供されます。
17 to mrs jane clemens and mrs moffett in st ${10}
17 mrs jane clemens and mrs moffett in st louis ${10}
それが私の考えが終わるところです。
期待/希望出力
あります。はい統計(非常に実際の出力がここに示されている出力と異なる可能性(ゼロではなく有限)があります。 9グラムの最初の2つの結果は、異なる単語の順序ではありません。最も一般的な10グラムの他の可能な部分は、最も一般的な9グラムのトップ10を見てみることができます。head
代わりに使用してください。head -n 2
それにもかかわらず、これは私たちが最も一般的な2つの10グラムを持っていることを保証するものではないと確信しています。しかし、私が達成したいことが何であるかを明確に表現できたらと思います。
17 to mrs jane clemens and mrs moffett in st louis
3 mrs jane clemens and mrs moffett in st louis honolulu
編集する予想される出力を(おそらく実際の出力ではなく、以前に使用した単純なモデルの出力)に変更する別のセットを見つけました。
17 to mrs jane clemens and mrs moffett in st louis
7 happiness in his home had been wounded and bruised almost
head -n 2
これは私が得た結果を示すために常に使用することです。
私はそれを得るためにここで使用するのと同じプロセスを経験したくありません。
$ grep -o "to mrs jane clemens and mrs moffett in st [^ ]\+" \
TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
17 to mrs jane clemens and mrs moffett in st louis
$ grep -o "mrs jane clemens and mrs moffett in st louis [^ ]\+" \
TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
3 mrs jane clemens and mrs moffett in st louis honolulu
2 mrs jane clemens and mrs moffett in st louis san
2 mrs jane clemens and mrs moffett in st louis no
2 mrs jane clemens and mrs moffett in st louis 224
1 mrs jane clemens and mrs moffett in st louis wash
1 mrs jane clemens and mrs moffett in st louis wailuku
1 mrs jane clemens and mrs moffett in st louis virginia
1 mrs jane clemens and mrs moffett in st louis the
1 mrs jane clemens and mrs moffett in st louis sept
1 mrs jane clemens and mrs moffett in st louis on
1 mrs jane clemens and mrs moffett in st louis hartford
1 mrs jane clemens and mrs moffett in st louis carson
編集する新しい2位の頻度を見つけるために使用されるコードは次のとおりです。
$ grep -o "[^ ]\+ happiness in his home had been wounded and bruised" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
6 shelley's happiness in his home had been wounded and bruised
1 his happiness in his home had been wounded and bruised
$ grep -o "shelley's happiness in his home had been wounded and [^ ]\+" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
6 shelley's happiness in his home had been wounded and bruised
$ grep -o "happiness in his home had been wounded and bruised [^ ]\+" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
7 happiness in his home had been wounded and bruised almost
$ grep -o "in his home had been wounded and bruised almost [^ ]\+" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
7 in his home had been wounded and bruised almost to
$ grep -o "his home had been wounded and bruised almost to [^ ]\+" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
7 his home had been wounded and bruised almost to death
$ grep -o "home had been wounded and bruised almost to death [^ ]\+" TWAIN_Mark_complete_parsed.txt | sort | uniq -c | sort -rn
1 home had been wounded and bruised almost to death thirdly
1 home had been wounded and bruised almost to death secondly
1 home had been wounded and bruised almost to death it
1 home had been wounded and bruised almost to death fourthly
1 home had been wounded and bruised almost to death first
1 home had been wounded and bruised almost to death fifthly
1 home had been wounded and bruised almost to death and
コメントで編集
@イニアンは本当にお疲れ様でした。コメント:
これはリリースノートに記載されています。github.com/beyondgrep/ack3/blob/dev/RELEASE-NOTES.md-これで、$1 から $9、$、$.、$&、$`、$'、および $+_ 変数のみ使用できます。
~のため未来の人々、一つ入れたいバージョン、今日アーカイブのRELEASE-NOTES
man
ページにはack
次の行があります。
$1 through $9
The subpattern from the corresponding set of capturing parentheses.
If your pattern is "(.+) and (.+)", and the string is "this and that',
then $1 is "this" and $2 is "that".
しかし、より高い数字を得る方法があったらと思います。からの情報によると、RELEASE-NOTES
その希望は大きく崩れたようです。
しかし、ack
、「標準」* NIXタイプのターミナルツールを使用するか、それを使用して解決策やハッキングを実行している人がいるかどうか疑問に思います。私の好みは順番にperl
、、、、です。似たようなものがある場合(例:コマンドラインの解析、grep
awk
sed
ack
いいえNLPツールキットベースのソリューション)、私はこれにも興味があります。
私はこれを新しい質問で尋ねるのが最善だと思います。ここに答えていただければ幸いです。新しい質問を投稿したら、ここにリンクを追加します。現在、これは同じ質問へのリンクにすぎません。。
コメント分析
Nグラム分析用に私のコーパスを準備するための解析は次のとおりです。
tr [:upper:] [:lower:] < TWAIN_Mark_complete_orig.txt | \
# upper case to lower case and avoid useless use of cat
tr '\n' ' ' | \
# newlines into spaces, so we can later make it one line, single-spaced
sed -E "s/[^a-z0-9 '*-]+//g" | \
# get rid of everything but letters, numbers, and a few other symbols (corpus)
awk '{$0=$0;$1=$1}1' > TWAIN_Mark_complete_parsed.txt && \
# collapse all multiple spaces to one space (includes tabs), save to output
:
はい、これらの内容はすべて1行に表示できます(末尾なし&& :
)。しかし、これは私が今やっていることをなぜしているのかを読み、説明するのが簡単になります。
システムの詳細
$ uname -a
CYGWIN_NT-10.0 MY_MACHINE 3.0.7(0.338/5/3) 2019-04-30 18:08 x86_64 Cygwin
$ bash --version | head -n 1
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
$ ack --version | head -n 2
ack v3.3.1 (standard build)
Running under Perl v5.26.3 at /usr/bin/perl.exe
$ systeminfo | sed -n 's/^OS\ *//p'
Name: Microsoft Windows 10 Enterprise
Version: 10.0.17134 N/A Build 17134
Manufacturer: Microsoft Corporation
Configuration: Member Workstation
Build Type: Multiprocessor Free
答え1
私はPerlの専門家ではありませんが、ここに可能なハッキングがあります。オールインワンのようです。ソースファイル、出力文字列内の単一文字のみack
を処理するようです。$
複数の文字を許可するように変更することは確かに機能しますが、単純にするには使用できます0..9
。たとえば、 and as と ( で示される ) をabc...
許可するように変更しました。$a
$b
$10
$11
diff -u
@@ -188,7 +188,7 @@
$opt_output =~ s/\\r/\r/g;
$opt_output =~ s/\\t/\t/g;
- my @supported_special_variables = ( 1..9, qw( _ . ` & ' + f ) );
+ my @supported_special_variables = ( 1..9, qw( a b _ . ` & ' + f ) );
@special_vars_used_by_opt_output = grep { $opt_output =~ /\$$_/ } @supported_special_variables;
# If the $opt_output contains $&, $` or $', those vars won't be
@@ -924,6 +924,8 @@
# on them not changing in the process of doing the s///.
my %keep = map { ($_ => ${$_} // '') } @special_vars_used_by_opt_output;
+ $keep{a} = $10;
+ $keep{b} = $11;
$keep{_} = $line if exists $keep{_}; # Manually set it because $_ gets reset in a map.
$keep{f} = $filename if exists $keep{f};
my $special_vars_used_by_opt_output = join( '', @special_vars_used_by_opt_output );
ただし、10番目の一致のみを希望する場合は、$+
次のように使用できます。最後に成功した検索パターンの最後の角かっこに一致するテキスト。
答え2
3つの代替ソリューション:
バージョン2の確認
ackバージョン2では、変数$10
$11
などが有効なようです。
$ echo 'abcdefghijklmn' |
ack '(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)' \
--output '$1 $2 $3 $11'
a b c k
$ ack --version
ack 2.24
Running under Perl 5.28.1 at /usr/bin/perl
その中でも入手するには重なる文字列は次のとおりです。
echo 'abcdefghijklmn' |
ack '(.)(?=(.)(.)(.)(.)(.)(.)(.)(.)(.)(.))' \
--output '$1 $2 $3 $11'
a b c k
b c d l
c d e m
d e f n
パール5
ただし、次のようにPerlで直接同じことを行うことができます。
echo 'abcdefghijklmn' |
perl -ne 'while($_ =~ /(.)(?=(.)(.)(.)(.)(.)(.)(.)(.)(.)(.))/g ){
print $1," ",$2," ",$11," ","\n" }'
a b k
b c l
c d m
d e n
したがって、単語を見つけて印刷するには(1つ以上のスペースで区切ってください):
echo "word1 word2 word3 word4 word5 word6" |
perl -ne 'while($_ =~ /(\S+) +(?=(\S+) +(\S+) +(\S+))/g ){$,=" ";print $1,$2,$3,$4,"\n" }'
word1 word2 word3 word4
word2 word3 word4 word5
word3 word4 word5 word6
印刷された行には後にスペースがあります(気にしないでください)。
パール6
:ov
または、(オーバーラップ)修飾子を使用してPerl6(Raku)を試すこともできます。
echo "one two three four five" |
perl6 -ne 'my @var = $_.match(/ <|w> \w+ [" "+ \w+]**2 <|w> /, :ov); say @var.join("\n") ;'
one two three
two three four
three four five
単一の数値を変更すると、他の数も一致します。
echo "one two three four five" |
perl6 -ne 'my @var = $_.match(/ <|w> \w+ [" "+ \w+]**3 <|w> /, :ov); say @var.join("\n") ;'
one two three four
two three four five
結果
Perl5では、結果は次のようになります。
perl -ne 'while($_ =~ /(\S+) +(?=(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+) +(\S+))/g ){
$,=" ";
print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,"\n"
}' TWAIN_Mark_complete_parsed.txt |
sort |
uniq -c |
sort -rn >Twain_10grams5.txt
Perl6はこれらの大規模なテストテキストを完了できません(メモリが多すぎます)(Perl6はまだ新すぎます)。 ackの使用はperl5よりはるかに遅いですが、ファイルは同じです。
head -n 10 Twain_10grams5.txt
17 to mrs jane clemens and mrs moffett in st louis
8 ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
7 in his home had been wounded and bruised almost to
7 his home had been wounded and bruised almost to death
7 happiness in his home had been wounded and bruised almost
6 shelley's happiness in his home had been wounded and bruised
5 was by the social fireside in the time of the
5 thing indeed if you would like to listen to it
5 laughable thing indeed if you would like to listen to
5 it was in this way that he found out that