grep은 고유한 대문자 문구를 추출합니다.

grep은 고유한 대문자 문구를 추출합니다.

다음 코드 조각은 입력 텍스트의 모든 대문자 목록을 생성합니다.

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

이제 길이에 상관없이 대문자로 표시된 고유한 문구의 발생 횟수를 추출하고 계산하고 싶습니다.

즉, 대문자 첫 글자를 공유하는 공백으로 구분된 단어의 고유한 문자열 수를 원합니다. 제공된 유일한 문구에는 구두점이나 대문자가 아닌 단어가 포함되어 있지 않으므로 두 문구 및 가 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단어를 공유하는 서로 다른 두 개의 고유한 구문입니다.

답변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 Input: Example Input또는 )Example\nInput 으로 변환됩니다.

-w해당 사항이 아니니 참고해주세요공간 분리단어, 단어 경계는 단어와 단어가 아닌 문자 사이에 있습니다(단어 문자는 숫자와 밑줄입니다). 너 원한다고 했지? 공백으로 구분된 단어United States이지만 이는 대신 United States. 또는 Mexico대신에 입력을 기대하는 것과 충돌합니다 .Mexico, Prussia

또한 [^ ]*[[:upper:]][^ ]*공백으로 구분된 단어와 일치합니다.포함하다대문자가 하나 이상 있지만 시작 부분에 있을 필요는 없습니다. 예를 들어, 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 코드를 세 가지 주요 부분으로 나누는 것부터 시작할 수 있습니다. 이 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.그대로 남아 있기 때문에 구두점에 대해 조치를 취해야 한다는 것을 즉시 알 수 있습니다 . 두 번째 시도:

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

관련 정보