次のテキストがあります。
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
この問題を解決するときに最初にすべきことは、作業に適したツールを選択することです。この問題では、各単語の最初の文字が1行に表示される回数を数える必要があります。 Pythongrep
やsed
Pythonは少なくともそれ自体では計算に精通していませんが、PythonとPythonは一般的な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
データの文字で索引付けされた連想配列に数を格納します。
2番目に最初の文字の1つに会うとすぐにその行を捨てます。このように、私たちは捨てないすべての行を印刷します。
このコードは言葉です最初文字は大文字です。すべて 大文字の単語の最初の文字をテストするには、次のコマンドを使用します。
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
私たちは、行に最初の文字が見つかりましたが、他の大文字の単語の先頭にのみ見つかる大文字の単語を探したいと言っています。これは少なくとも1つのマッチングを意味しますが、我々はそのようなマッチングを望んでいないので、目的の-v
出力を得るためにマッチングの意味を反転します。
編集:@theirの観察に基づいて大文字の単語を見つけるように修正しました。
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;
}
入力した条件によっては入力入力行が印刷されないため、入力に 2 つの出力例行を追加しました。
$ ./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への入力を1行ずつ読み取るには、コマンドラインフラグを使用します-ne
。入力はスペースで区切られwords
、各単語はチェック(使用map
)およびフィルタリング(使用comb
)され、大文字で始まる単語を検索します(^<upper>
正規表現を使用)。次に、Bag
文字を -ged し、発生回数を計算し、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