
다음 텍스트가 있습니다.
FOUR MILLION, EIGHT HUNDRED AND FIFTY-SEVEN THOUSAND, FIVE HUNDRED AND THIRTEEN innovating
FORTY-NINE MILLION, ONE HUNDRED AND EIGHTY THOUSAND, TWO HUNDRED AND FORTY-EIGHT championed
FORTY-SEVEN MILLION, NINE HUNDRED AND FIFTY-TWO THOUSAND, EIGHT HUNDRED AND SIX swashbuckling
NINE HUNDRED AND SIXTY-ONE THOUSAND, SIX HUNDRED AND THIRTY-ONE sprinklers
FORTY-TWO MILLION, TWO HUNDRED AND SIXTY-SIX THOUSAND, THREE HUNDRED AND SEVENTY-TWO furloughs
SEVEN MILLION, FOUR HUNDRED AND SEVENTEEN THOUSAND, FOUR HUNDRED AND FORTY-TWO panicky
THREE HUNDRED AND SEVENTY-NINE THOUSAND, FIVE HUNDRED AND TWENTY-EIGHT anchovies
FIVE MILLION, EIGHT HUNDRED AND FIFTY-NINE THOUSAND, FOUR HUNDRED AND SIXTY-FOUR excesses
............
대문자로 된 줄의 모든 단어가 다른 문자로 시작하는 줄을 사용 grep
하거나 인쇄하는 방법은 무엇입니까 ?sed
예를 들어:
FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGH
답변1
이와 같은 문제를 해결할 때 가장 먼저 해야 할 일은 작업에 적합한 도구를 선택하는 것입니다. 이 문제에서는 각 단어의 첫 글자가 한 줄에 나타나는 횟수를 세어야 합니다. 둘 다 grep
적어도 sed
그 자체로는 계산에 능숙하지 않지만 awk
범용 프로그래밍 언어에 더 가깝습니다. 작업을 해결하기 위해 단일 도구를 사용하려면 이 도구 awk
가 더 적합할 것입니다.
awk '{
delete count
for (i = 1; i <= NF; ++i) {
ch = substr($i,1,1)
if (ch == toupper(ch) && count[ch]++)
next
}
print
}' file
코드는 각 줄에 있는 모든 단어의 첫 대문자(공백으로 구분된 하위 문자열인 단어)의 발생 횟수를 계산합니다. count
데이터의 문자로 인덱싱된 연관 배열에 개수를 유지합니다 .
두 번째로 첫 글자 중 하나를 발견하자마자 줄을 버립니다. 이런 방식으로 폐기하지 않는 각 줄을 인쇄합니다.
이 코드는 단어가첫 번째문자는 대문자입니다. 모두 대문자인 단어의 첫 문자를 테스트하려면 대신 다음을 사용하십시오.
awk '{
delete count
for (i = 1; i <= NF; ++i)
if ($i != toupper($i) && count[substr($i,1,1)]++)
next
print
}' file
다음 문제는 코드를 이해하는 것입니다. 당신은갖다이제 코드가 작동하고 작동하지만 이유를 모를 수도 있습니다. 더 중요한 것은 약간 다른 작업을 수행하기 위해 수정하는 방법이나 발견한 일부 극단적인 경우에서 갑자기 실패하는 경우 이를 수정하는 방법을 모를 수도 있다는 것입니다.
awk
시작으로 매뉴얼 의 각 비트를 찾아보면 코드를 더 잘 알 수 있습니다 . 그런 다음 내가 왜 다른 곳이 아닌 특정 장소에 글을 썼는지 이해하지 못할 경우 delete count
이에 대해 또 다른 질문을 할 수 있습니다. 또는 더 나은 방법은 코드를 실험하고 어떤 구체적인 방식으로 코드가 깨지는지 기록하는 것입니다.
답변2
정규식을 사용하여 입력을 검색하고 원하는 출력을 얻을 수 있습니다.
grep
우리는 첫 번째 문자가 줄 아래에서 발견되지만 다른 대문자 단어의 시작 부분에서만 발견되는 대문자 단어를 찾으라고 말하고 있습니다 . 이는 적어도 하나의 일치를 의미하지만 우리는 그러한 일치를 원하지 않기 때문에 -v
원하는 출력을 얻기 위해 일치의 의미를 반전시킵니다.
편집됨: @they의 관찰을 기반으로 대문자 단어를 찾도록 수정되었습니다.
grep -v '\<\([A-Z]\)[A-Z]\{1,\}\>.*\<\1[A-Z]\{1,\}\>' file
답변3
다음 Perl 스크립트는 지나치게 장황하므로 상당히 줄일 수 있지만 알고리즘을 암호처럼 간결하기보다는 명확하게 보여주기 위해 작성되었습니다.
$ cat caps.pl
#!/usr/bin/perl
use strict;
MAIN: while(<>) {
# skip lines without a capital letter
next unless /[A-Z]/;
# hash to hold the counts of the first letters of each word,
# reset to empty for every input line
my %letters = ();
foreach my $w (split /[-\s]+/) {
# ignore "words" not beginning with a letter
next unless $w =~ m/^[[:alpha:]]/;
# get the first character of the word
my $l = substr($w,0,1);
# uncomment if you want upper- and lower-case to be treated
# as the same letter:
#$l = uc($l);
$letters{$l}++;
# If we've seen this letter before on this line, skip to the
# next input line.
next MAIN if $letters{$l} > 1;
};
# the input line has no first letters which appear more than once, so print it.
print;
}
귀하가 제공한 기준에 따라 샘플 입력 줄이 인쇄되지 않으므로 두 개의 샘플 출력 줄을 입력에 추가했습니다.
$ ./caps.pl input.txt
FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGHT
답변4
Raku(이전의 Perl_6) 사용
raku -ne '.put if .words.map(*.comb(/ ^<upper> /)).Bag.values.max == 1;'
샘플 입력:
FOUR MILLION, EIGHT HUNDRED AND FIFTY-SEVEN THOUSAND, FIVE HUNDRED AND THIRTEEN innovating
FORTY-NINE MILLION, ONE HUNDRED AND EIGHTY THOUSAND, TWO HUNDRED AND FORTY-EIGHT championed
FORTY-SEVEN MILLION, NINE HUNDRED AND FIFTY-TWO THOUSAND, EIGHT HUNDRED AND SIX swashbuckling
NINE HUNDRED AND SIXTY-ONE THOUSAND, SIX HUNDRED AND THIRTY-ONE sprinklers
FORTY-TWO MILLION, TWO HUNDRED AND SIXTY-SIX THOUSAND, THREE HUNDRED AND SEVENTY-TWO furloughs
SEVEN MILLION, FOUR HUNDRED AND SEVENTEEN THOUSAND, FOUR HUNDRED AND FORTY-TWO panicky
THREE HUNDRED AND SEVENTY-NINE THOUSAND, FIVE HUNDRED AND TWENTY-EIGHT anchovies
FIVE MILLION, EIGHT HUNDRED AND FIFTY-NINE THOUSAND, FOUR HUNDRED AND SIXTY-FOUR excesses
FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGH
샘플 출력:
FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGH
이 문제는 이전에 Perl6(2019년에 이름 변경)으로 알려진 프로그래밍 언어의 새 이름인 Raku의 한 줄을 사용하여 쉽게 해결됩니다.
간단히 말해서 입력은 명령줄 플래그를 사용하여 Raku에 라인 단위로 읽혀집니다 -ne
. 입력은 공백으로 구분된 으로 나뉘며 words
, 각 단어는 대문자로 시작하는 단어에 대해 검사( 사용 map
) 및 필터링( 사용 )됩니다( 정규식 사용). 그런 다음 해당 문자는 -ged되어 발생 횟수를 계산하고 발생이 존재하는 줄(예: 중복 문자 없음)만 반환됩니다.comb
^<upper>
Bag
max == 1
이 문제에 대한 "단어"가 무엇인지에 대한 설명이 있는 것 같습니다. 하이픈으로 연결된 단어를 별도의 단어로 계산하려면 먼저 .split("-")
메서드 체인의 시작 부분(앞 .words
)에 추가하여 하이픈으로 분할하세요.
위의 Raku 코드가 어떻게 작동하는지에 대한 아이디어를 제공하기 위해 코드의 핵심은 다음과 같습니다.~와 함께루틴 split
하지만없이조건부 if
및 조건부 없음 max
:
raku -ne '.split("-").words.map(*.comb(/ ^<upper> /)).Bag.put;'
H(2) M A(2) T(2) E S F(3)
T(2) N E(2) H(2) O F(2) M A(2)
M S(2) T(2) N A(2) E H(2) F(2)
O(2) H(2) S(2) A(2) T(2) N
M H(2) A(2) S(3) F T(5)
S(2) F(3) A(2) H(2) T(2) M
T(3) H(2) S E F N A(2)
H(2) T S M N A(2) F(4) E
A E F H N T
E T F N H S A
https://docs.raku.org/언어/regexes#Pre Defined_character_classes
https://raku.org