제가 검색을 잘못한 것일지도 모른다고 생각했지만 아무런 답도 찾지 못했습니다. 중복된 내용이 있으면 알려주시면 삭제하겠습니다.
문제 배경
나는 ack
(협회), Perl 5를 내부적으로 사용하여 n-그램, 특히 고차 n-그램을 얻습니다. 내가 아는 구문(기본적으로 가장 많이 $9
)을 사용하면 최대 9g까지 얻을 수 있지만 10g은 얻을 수 없습니다. 사용하면 접미사 가 $10
제공됩니다 . 그런 식으로 문제가 해결되지 않았습니다 . 그래요$1
0
$(10)
${10}
아니요Language Modeling Toolkit을 사용하는 솔루션에 관심이 있어 ack
.
내가 사용한 데이터 세트 중 하나는 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-gram에서 얻은 결과는 괜찮습니다. 코드와 부분 결과는 다음과 같습니다.
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
처음 두 줄의 출력이 제공됩니다.
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
처음 두 줄의 출력이 제공됩니다.
17 to mrs jane clemens and mrs moffett in st ${10}
17 mrs jane clemens and mrs moffett in st louis ${10}
그것이 내 생각이 끝나는 곳입니다.
예상/원하는 출력
있습니다.예통계(매우실제 출력이 여기에 표시된 출력과 다를 가능성(0이 아니고 유한)이 있습니다. 9-gram에 대한 처음 두 결과는 서로 다른 단어 순서가 아닙니다. 가장 일반적인 10그램의 다른 가능한 부분은 가장 일반적인 9그램 상위 10개를 살펴보면서 찾을 수 있습니다 . head
대신 사용하세요. head -n 2
그럼에도 불구하고 이것이 우리가 가장 일반적인 두 가지 10g을 가지고 있다는 것을 보장하지는 않는다고 확신합니다. 하지만 제가 이루고 싶은 것이 무엇인지 명확하게 표현할 수 있었으면 좋겠습니다.
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
:
예, 이 모든 내용은 한 줄에 표시될 수 있습니다(후행 없이 && :
). 하지만 이렇게 하면 내가 지금 하고 있는 일을 왜 하고 있는지 읽고 설명하기가 더 쉬워집니다.
시스템 세부정보
$ 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
세 가지 대체 솔루션:
버전 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
따라서 단어를 찾아 인쇄하려면(하나 이상의 공백으로 구분):
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