grepは一意の大文字のフレーズを抽出します。

grepは一意の大文字のフレーズを抽出します。

次のコードスニペットは、入力テキストのすべての大文字のリストを生成します。

grep -o '[^ ]*[[:upper:]][^ ]*' book_text.txt > Capitalized_words.txt

ここで、長さに関係なく、大文字でマークされた固有のフレーズの発生回数を抽出して計算したいと思います。

つまり、大文字の最初の文字を共有するスペースで区切られた単語の一意の文字列数が必要です。提供された唯一のフレーズには、句読点や大文字以外の単語が含まれていないため、2つのフレーズとにUniversity of British Columbiaなります。UniversityBritish Columbia

入力例:

Harvard archaeologists in Mexico also participated in the International
School of American Archaeology and Ethnology in Mexico City with scholars from
Mexico, Prussia and the United States.

予想出力:

1 - Harvard
1 - International School
1 - American Archaeology
1 - Ethnology
1 - Mexico City
2 - Mexico
1 - Prussia
1 - United States

例では、とは、Mexico単語Mexico Cityを共有する2つの異なる固有の構文です。

答え1

GNU grepPCREを使用してビルドする場合は、以下をサポートします。

$ grep -Pow '(\p{Lu}\w*)(\s+(?1))*' input | sort | uniq -c
      1 American Archaeology
      1 Ethnology
      1 Example Input
      1 Harvard
      1 International School
      2 Mexico
      1 Mexico City
      1 Prussia
      1 United States

または:

<input tr -s '[:space:]' '[ *]' |
  grep -Pow '(\p{Lu}\w*)(\s+(?1))*' |
  sort |
  uniq -c

空白文字(改行文字を含む)のすべてのシーケンスは、最初に単一の空白(たとえばExample InputExample Inputまたは)Example\nInputに変換されます。

-w該当しないので参考にしてください空間分離単語、単語の境界は単語と単語ではなく文字の間にあります(単語の文字は数字と下線です)。あなたが欲しいと言った? スペースで区切られた単語United Statesただし、これは代わりにまたは代わりUnited States.Mexico入力を期待することと矛盾します。Mexico, Prussia

また、[^ ]*[[:upper:]][^ ]*スペースで区切られた単語と一致します。含む大文字が 1 つ以上ありますが、先頭にある必要はありません。たとえば、fooBarまたはと一致します0xAB+12(?<!\S)\p{Lu}\S*大文字で始まるスペースで区切られた単語が必要です。

$ grep -Po '(?<!\S)(\p{Lu}\S*)(\s+(?1))*' input | sort | uniq -c
      1 American Archaeology
      1 Ethnology
      1 Example Input:
      1 International School
      1 Mexico
      1 Mexico City
      1 Mexico, Prussia
      1 United States."

Harvard全行があり、スペースExample Input: "Havard ..."で区切られた単語が大文字で始まらないため、欠落しています。)input"Harvard

in途中でいくつかを追加することもできます。of

$ grep -Pow '(\p{Lu}\w*)((\s+(in|of))?\s+(?1))*' input | sort | uniq -c
      1 Ethnology in Mexico City
      1 Example Input
      1 Harvard
      1 International School of American Archaeology
      2 Mexico
      1 Prussia
      1 United States

\w英語以外のテキストを扱う場合に置き換えることもできます((?=\w)\X)。つまり、単語文字、一致単語文字で始まる文字素クラスタ

$ echo $'Universidad Nacional Auto\u0301noma de Me\u0301xico' |
  grep -Pow '(\p{Lu}\w*)((\s+(in|of|de))?\s+(?1))*' | sort | uniq -c
      1 Me
      1 Universidad Nacional Auto
$ echo $'Universidad Nacional Auto\u0301noma de Me\u0301xico' |
  grep -Pow '((?=\p{Lu})\X((?=\w)\X)*)((\s+(in|of|de))?\s+(?1))*' |
  sort | uniq -c
      1 Universidad Nacional Autónoma de México

Barではまだ一致しています$'foo\u0301Bar'

さらに、単語の文字/小文字および/または区切り文字で覆われる名前の構成を具体化する必要があるかもしれません。樹脂の台所オブライアン小学校ジャン・ポール・サルトル高校、等。

これらすべてをまとめると、次のように終わります。

first_grapheme='(?: (?= \p{Lu} ) \X )'
word_character="[\w'-]"
 word_grapheme="(?: (?= $word_character ) \X )"
          word="$first_grapheme $word_grapheme *"
     separator='(?: [ ] (?: in | on | of | de | en ) )? [ ]'

<input tr -s '[:space:]' '[ *]' |
  grep -Po "(?x) (?<! \pM | $word_character ) $word (?: $separator $word ) *" |
  sort |
  uniq -c

答え2

Raku(以前のPerl_6)の使用

raku -e '.subst(",", " and ", :g).subst(".", " ", :g).comb(/ <( [ <:Lu> <:Ll>+ \h+ ]+ )> <:Ll>* /).map(*.trim-trailing).Bag.antipairs.join("\n").say for lines();'

入力例:

Harvard archaeologists in Mexico also participated in the International School of American Archaeology and Ethnology in Mexico City with scholars from Mexico, Prussia and the United States.

出力例(最終):

1   Ethnology
1   Prussia
2   Mexico
1   American Archaeology
1   Harvard
1   Mexico City
1   International School
1   United States

興味深い質問は、Rakuがかなり進化した正規表現エンジン(下の参照によるとPCREよりも進化している)と考えられているため、Rakuを使用してこの問題を解決することにしました。

Rakuコードを3つの主要部分に分割することから始めることができます。このcombセクションでは、正規表現マッチングを使用してテキスト入力を必須要素に分割します。あなたはすでに多くのシンボル(または概念)に精通しています。たとえば、Rakuのキャプチャタグはです<(…)>。この部分だけが1を返しましたが、このcomb部分だけが予想値である8/9を返しました。

raku -e '.comb(/ <( [ <:Lu> <:Ll>+ \h+ ]+ )> <:Ll>* /).join("\n").say for lines();'

出力例(試行#1):

Harvard 
Mexico 
International School 
American Archaeology 
Ethnology 
Mexico City 
Prussia 
United

Mexico,値と部分値の両方がStates.そのまま残っているため、句読点に対処する必要があることがすぐにわかります。 2回目の試み:

raku -e '.subst(",", " and ", :g).subst(".", " ", :g).comb(/ <( [ <:Lu> <:Ll>+ \h+ ]+ )> <:Ll>* /).join("\n").say for lines();'

出力例(試行#2):

Harvard 
Mexico 
International School 
American Archaeology 
Ethnology 
Mexico City 
Mexico 
Prussia 
United States

上記は予想値である9/9を返します。最後にコンマを、ピリオドを空白に置き換える,ことにしました。 (テキストに対する最善の措置を決定する必要があります)。and.

一番上の最終結果を取得するには、.map(*.trim-trailing).Bag.antipairs目的の結果を生成するコードに呼び出しを挿入します。

https://slides.yowconference.com/yowwest2015/Conway-EverythingYouKnowAboutRegexesIsWrong.pdf
https://youtu.be/ubvSjW6Nyqk
https://raku.org

関連情報