各単語が異なる文字で始まる大文字で行を印刷します。

各単語が異なる文字で始まる大文字で行を印刷します。

次のテキストがあります。

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行に表示される回数を数える必要があります。 PythongrepsedPythonは少なくともそれ自体では計算に精通していませんが、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

関連情報