각 단어가 다른 문자로 시작하는 대문자로 줄을 인쇄합니다.

각 단어가 다른 문자로 시작하는 대문자로 줄을 인쇄합니다.

다음과 같은 텍스트가 있습니다.

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

이와 같은 문제를 해결할 때 가장 먼저 해야 할 일은 작업에 적합한 도구를 선택하는 것입니다. 이 문제에서는 각 단어의 첫 글자가 한 줄에 나타나는 횟수를 세어야 합니다. Python grep이나 sedPython은 적어도 그 자체로는 계산에 능숙하지 않은 반면, 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데이터의 문자로 인덱싱된 연관 배열에 개수를 저장합니다 .

두 번째로 첫 글자 중 하나를 만나면 즉시 그 줄을 버립니다. 이런 식으로 우리는 버리지 않는 모든 줄을 인쇄합니다.

이 코드는 단어가첫 번째문자는 대문자입니다. 모두 대문자로 된 단어의 첫 번째 문자를 테스트하려면 다음 명령을 사용하십시오.

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원하는 출력을 얻기 위해 일치의 의미를 뒤집습니다.

편집: @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;
}

귀하가 제공한 조건에 따라 예제 입력 행이 인쇄되지 않으므로 입력에 두 개의 예제 출력 행을 추가했습니다.

$ ./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) 및 필터링( 사용 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

관련 정보