Ist es möglich, die Buchstaben eines Wortes in einer Textzeile zu sortieren?

Ist es möglich, die Buchstaben eines Wortes in einer Textzeile zu sortieren?

Ich habe also eine Datei voller Testbefehle, die ich gerne für einige meiner Funktionen ausführe, um sicherzustellen, dass sie alle möglichen Situationen richtig handhaben. Es macht jedoch keinen Sinn, doppelte Befehle zu haben. Hier sind einige Beispiele:

rap ,Xflg MIT X11           
rap ,XPBfl 'MITER'
rap ,Bflg share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

... meine Funktion 'rap' verwendet ein Komma statt eines Bindestrichs, um den Beginn von Buchstabenoptionen anzuzeigen, dann folgt ein Argument. Da die Reihenfolge dieser Optionen keine Rolle spielt:

rap ,Bf X11
rap ,fB X11

... sind genau derselbe Befehl. Natürlich ist es einfach, doppelte Zeilen aus der Datei zu entfernen. Um das obige Problem zu vermeiden, würde ich die Optionen gerne alphabetisch sortieren, sodass das obige Ergebnis lautet:

rap ,Bf X11
rap ,Bf X11

... und dann könnte ich die Duplikate löschen. Kann so etwas ohne Heldentaten gemacht werden? Beachten Sie, dass dies nicht das Sortieren „nach“ der Liste der Optionen ist, sondern das Sortieren der Optionen selbst.

Antwort1

Eine andere perlVariante:

$ perl -pe 's{^rap ,\K\S+}{join "", sort split //, $&}e' file
rap ,Xfgl MIT X11
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

Für Ihre zusätzliche Anforderung, dass Kleinbuchstaben vor Großbuchstaben stehen müssen, können Sie sich auf die Tatsache verlassen, dass in ASCII 'x'gilt 'X' ^ 32(und 'X'ist 'x' ^ 32):

$ perl -pe 's{^rap ,\K\S+}{join "", sort {(ord($a)^32) <=> (ord($b)^32)} split //, $&}e' file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

Antwort2

Sie könnten Perl verwenden, um eine Folge von Wortzeichen nach einem Komma zu erfassen, das Ergebnis in ein Array aufzuteilen, dieses zu sortieren und das Ergebnis zu ersetzen:

$ perl -pe 's{(?<=,)(\w+)}{join "", sort split(//, $1)}e' yourfile 
rap ,Xfgl MIT X11           
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep    
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11

Wie gewünscht gibt es hier eine (wahrscheinlich nicht optimale) Möglichkeit, alle Kleinbuchstaben vor allen Großbuchstaben zu sortieren:

$ perl -pe 's{(?<=,)(\w+)}{@opts = split(//,$1); join "", 
    (sort grep /[[:lower:]]/,@opts), (sort grep /[^[:lower:]]/, @opts)
  }e' yourfile 
rap ,fglX MIT X11           
rap ,flBPX 'MITER'
rap ,fglB share git-grep    
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

Antwort3

Verwendung von GNU awk fürsorted_inund da wir gawk sowieso verwenden, ein paar andere praktische, aber unnötige Erweiterungen, können wir dieDekorieren-Sortieren-Entdekorieren - Redewendungindem Sie es 1vor alle Kleinbuchstaben und 2vor alle Großbuchstaben setzen, um zu erzwingen, dass alle Kleinbuchstaben vor den Großbuchstaben sortiert werden, und diese Verzierungen dann vor dem Drucken wieder entfernen:

$ cat tst.awk
BEGIN { PROCINFO["sorted_in"] = "@val_str_asc" }
match( $0, /^(\s*\S+\s*,)(\S+)(.*)/, a ) {
    gsub( /[[:lower:]]/, "1 &,", a[2] )        # Decorate
    gsub( /[[:upper:]]/, "2 &,", a[2] )

    sorted = ""
    split(a[2],opts,",")
    for ( idx in opts ) {                      # Sort
        sorted = sorted opts[idx]
    }

    gsub( /[[:digit:] ,]/, "", sorted )        # Undecorate
    $0 = a[1] sorted a[3]
}
{ print }

$ awk -f tst.awk file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11

Antwort4

Wenn wir das Komma in der Eingabedatei durch einen Bindestrich ersetzen, können wir die Optionen der Funktion getoptswie gewohnt analysieren .rap

Diese Änderung kann mit durchgeführt werden . Unter der Annahme, dass wir immer nur am Anfang einer Zeile in sedändern müssen , sähe das folgendermaßen aus:rap ,rap -

sed 's/^rap ,/rap -/' file.in >file

Wir könnten dann einfach die generierte Datei in unserem Skript als Quelle verwenden, . ./filevorausgesetzt, die rapFunktion wurde zuvor deklariert.

So analysieren Sie die Optionen in der rapFunktion:

rap () {
        OPTIND=1

        unset -v B_flag P_flag X_flag
        unset -v b_flag f_flag g_flag l_flag

        while getopts BPXbfgl opt; do
                case $opt in
                        B) B_flag=true ;;
                        P) P_flag=true ;;
                        X) X_flag=true ;;
                        b) b_flag=true ;;
                        f) f_flag=true ;;
                        g) g_flag=true ;;
                        l) l_flag=true ;;
                        *) echo 'Error' >&2; return 1
                esac
        done
        shift "$(( OPTIND - 1 ))"

        # Act on set flags here.

        if "${f_flag-false}"; then
                echo 'The -f option was used'
        fi

        # The non-options are available in "$@".

        printf 'Other argument: %s\n' "$@"
        printf -- '---\n'
}

Beachten Sie, dass wir durch das Festlegen der Flagvariablen in der whileSchleife und das Bearbeiten dieser nach der Schleife vermeiden, dass doppelte Optionen mehrfach bearbeitet werden.

verwandte Informationen