Drucken Sie Zeilen, bei denen jedes Wort der Zeile mit Großbuchstaben mit einem anderen Buchstaben beginnt

Drucken Sie Zeilen, bei denen jedes Wort der Zeile mit Großbuchstaben mit einem anderen Buchstaben beginnt

Ich habe diesen Text:

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

 ............

Wie verwende grepoder seddrucke ich Zeilen, bei denen jedes Wort der Zeile mit Großbuchstaben mit einem anderen Buchstaben beginnt?

Zum Beispiel:

FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGH

Antwort1

Die erste Aufgabe bei der Lösung eines solchen Problems besteht darin, das richtige Werkzeug für die Aufgabe auszuwählen. Bei diesem Problem müssen wir zählen, wie oft der Anfangsbuchstabe jedes Wortes in einer Zeile vorkommt. Sowohl als auch grepsind sedbekanntermaßen schlecht beim Zählen, zumindest für sich allein, während awkes sich eher um eine allgemeine Programmiersprache handelt. Wenn wir ein einzelnes Werkzeug zur Lösung der Aufgabe verwenden möchten, awkwäre wahrscheinlich besser geeignet.

awk '{
    delete count
    for (i = 1; i <= NF; ++i) {
        ch = substr($i,1,1)
        if (ch == toupper(ch) && count[ch]++)
            next
    }
    print
}' file

Der Code zählt die Vorkommen der Anfangsbuchstaben aller Wörter in jeder Zeile (ein Wort ist eine durch Leerzeichen getrennte Teilzeichenfolge). Wir speichern die Anzahl im assoziativen Array count, das nach den Buchstaben aus den Daten indiziert ist.

Sobald wir einen der Anfangsbuchstaben zum zweiten Mal sehen, verwerfen wir die Zeile. Jede Zeile, die wir nicht auf diese Weise verwerfen, drucken wir aus.

Dieser Code berücksichtigt nur, ob das WortErsteZeichen ist groß geschrieben. Um das erste Zeichen von Wörtern zu testen, die alle groß geschrieben sind, verwenden Sie stattdessen Folgendes:

awk '{
    delete count
    for (i = 1; i <= NF; ++i)
        if ($i != toupper($i) && count[substr($i,1,1)]++)
            next
    print
}' file

Das nächste Problem ist, den Code zu verstehen. Sie habenbekommenden Code jetzt und er funktioniert, aber Sie wissen vielleicht nicht, warum. Und was noch wichtiger ist: Sie wissen vielleicht nicht, wie Sie ihn ändern können, damit er etwas leicht anderes macht, oder wie Sie ihn korrigieren können, wenn er in einem Grenzfall, den Sie entdecken, plötzlich fehlschlägt.

Sie können den Code besser kennenlernen, indem Sie awkzunächst jedes Bit im Handbuch nachschlagen. Wenn Sie dann nicht verstehen, warum ich delete countan dieser bestimmten Stelle und nicht woanders geschrieben habe, können Sie eine andere Frage dazu stellen oder, noch besser, mit dem Code experimentieren und feststellen, inwiefern er konkret kaputt geht.

Antwort2

Sie können den regulären Ausdruck verwenden, um die Eingabe zu scannen und die gewünschte Ausgabe zu erhalten.

Wir sagen, wir grepsollen nach einem Wort in Großbuchstaben suchen, dessen erster Buchstabe weiter unten in der Zeile vorkommt, aber nur am Anfang eines anderen Wortes in Großbuchstaben. Da dies mindestens eine solche Übereinstimmung impliziert, wir aber keine solchen Übereinstimmungen wollen, kehren wir -vden Sinn der Übereinstimmung um, um die gewünschte Ausgabe zu erhalten.

Bearbeitet: Basierend auf den Beobachtungen von @they wurde es so geändert, dass nach Wörtern in Großbuchstaben gesucht wird.

grep -v  '\<\([A-Z]\)[A-Z]\{1,\}\>.*\<\1[A-Z]\{1,\}\>'  file

Antwort3

Das folgende Perl-Skript ist übermäßig ausführlich und könnte erheblich gekürzt werden, wurde jedoch geschrieben, um den Algorithmus klar und nicht kryptisch prägnant darzustellen:

$ 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;
}

Keine Ihrer Beispiel-Eingabezeilen ließ sich mit den von Ihnen angegebenen Kriterien drucken, daher habe ich Ihre beiden Beispiel-Ausgabezeilen zur Eingabe hinzugefügt:

$ ./caps.pl input.txt 
FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGHT

Antwort4

Verwenden von Raku (früher bekannt als Perl_6)

raku -ne '.put if .words.map(*.comb(/ ^<upper> /)).Bag.values.max == 1;'  

Beispieleingabe:

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

Beispielausgabe:

FIFTY THOUSAND, NINE HUNDRED AND EIGHTEEN
FOURTEEN THOUSAND, SEVEN HUNDRED AND NINETY-EIGH

Dieses Problem lässt sich einfach mit einem Einzeiler in Raku lösen, dem neuen Namen der Programmiersprache, die früher als Perl6 bekannt war (2019 umbenannt).

Kurz gesagt wird die Eingabe zeilenweise in Raku eingelesen, indem die -neBefehlszeilenflags verwendet werden. Die Eingabe wird in durch Leerzeichen getrennte s aufgeteilt words, jedes dieser Wörter wird untersucht (mit map) und combauf Wörter gefiltert (mit ), die mit einem Großbuchstaben beginnen (mithilfe von ^<upper>Regex). Diese Buchstaben werden dann Bagmit -ged versehen, wodurch die Anzahl der Vorkommen gezählt wird, und es werden nur Zeilen zurückgegeben, in denen max == 1Vorkommen vorhanden sind (d. h. keine doppelten Buchstaben).

Es scheint einige Kommentare dazu zu geben, was ein „Wort“ für dieses Problem ausmacht. Wenn Sie Wörter mit Bindestrich als separate Wörter zählen möchten, trennen Sie sie zuerst nach Bindestrichen, indem Sie sie .split("-")am Anfang der Methodenkette hinzufügen (vorher .words).

Um Ihnen eine Vorstellung davon zu geben, wie der obige Raku-Code funktioniert, hier der Kern des Codesmitdie splitRoutine, aberohnedas ifKonditional und ohne das maxKonditional:

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/language/regexes#Predefined_character_classes
https://raku.org

verwandte Informationen