Schreiben Sie eine Funktion, die prüft, ob eine Zeichenfolge mit etwas beginnt oder etwas enthält

Schreiben Sie eine Funktion, die prüft, ob eine Zeichenfolge mit etwas beginnt oder etwas enthält

Ich möchte eine Funktion schreiben, die prüft, ob eine gegebene Variable, sagen wir var, mit einem der Wörter in einer gegebenen Liste von Zeichenfolgen beginnt. Diese Liste ändert sich nicht.

Zur Instanziierung tun wir so, als ob ich prüfen möchte, ob mit oder varbeginnt .aaabc3@3

Außerdem möchte ich prüfen, ob vardas Zeichen enthalten ist >.

Nehmen wir an, diese Funktion wird aufgerufen check_func. Meine beabsichtigte Verwendung sieht ungefähr so ​​aus:

if check_func "$var"; then
    do stuff
fi

Beispielsweise sollte es für aardvark, abcdef, [email protected]und „Dinge erledigen“ 12>5.


Ich habe gesehendiese SO-Fragewenn ein Benutzer einen Teil der Arbeit bereitstellt:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

Meine Idee ist, dass ich die oben genannte Liste durchlaufe und diese Funktion verwende. Meine Schwierigkeit besteht darin, dass ich nicht genau verstehe, wie das Beenden (oder was auch immer das Zurückkehren ersetzt) ​​erfolgen soll, damit dies funktioniert.

Antwort1

check_prefixes () {
    value=$1

    for prefix in aa abc 3@3; do
        case $value in
            "$prefix"*) return 0
        esac
    done

    return 1
}

check_contains_gt () {
    value=$1

    case $value in
        *">"*) return 0
    esac

    return 1
}

var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
    printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi

Ich habe die Tests auf zwei Funktionen aufgeteilt. Beide verwenden case ... esacund geben Erfolg (Null) zurück, sobald dieser festgestellt werden kann. Wenn nichts übereinstimmt, wird Fehler (1) zurückgegeben.

Um die Liste der Präfixe dynamischer zu gestalten, könnte man die erste Funktion auch so schreiben:

check_prefixes () {
    value=$1
    shift

    for prefix do
        case $value in
            "$prefix"*) return 0
        esac
    done

    return 1
}

(der zu prüfende Wert ist das erste Argument, das wir in der Argumentenliste der Funktion speichern valueund dann wieder entfernen; dann iterieren wir über die restlichen Argumente) und rufen es dann auf alsshift

check_prefixes "$var" aa abc 3@3

Die zweite Funktion könnte auf ähnliche Weise geändert werden in

check_contains () {
    value=$1
    shift

    case $value in
        *"$1"*) return 0
    esac

    return 1
}

(um nach einer beliebigen Teilzeichenfolge zu suchen) oder

check_contains_oneof () {
    value=$1
    shift

    for substring do
        case $value in
            *"$substring"*) return 0
        esac
    done

    return 1
}

(um nach einer beliebigen Anzahl von Teilzeichenfolgen zu suchen)

Antwort2

Für Bash:

Mithilfe der Eigenschaften von regulären Ausdrücken können Sie startmit ^und containdurch nichts schreiben.

Die Liste der zu prüfenden regulären AusdrückeStartmit aa abcoder 3@3undenthält >Ist:

^aa ^abc ^3@3 >

Machen Sie daraus einrichtigListe in Anführungszeichen setzen und Bash auffordern, reguläre Ausdrücke zu verwenden ( =~):

check_func() {
               matched=1
               for test_regex in '^aa' '^abc' '^3@3' '>'; do
                   if [[ $var =~ $test_regex ]] ; then
                       matched=0
                       break 
                   fi
               done
               return "$matched"
              }

var='aaIsAMatch'
if check_func; then
    echo "A match was found"
fi

Die Funktion hat die Liste der Übereinstimmungen und den Namen der Variable fest codiert.

Angeben der Liste der regulären Ausdrücke in einer Array-Variablen und des zu testenden Werts für das erste Argument:

check_func() {
               local matched; matched=1
               for t in "${test_regex[@]}"; do
                   [[ $1 =~ $t ]] && { matched=0; break; } 
               done
               return "$matched"
              }


test_regex=('^aa' '^abc' '^3@3' '>')

if check_func 'aaIsAMatch'; then
    echo "A match was found"
fi

Die Funktion könnte weiter verbessert werden, um den Namen einer Variablen (anstelle eines Werts) als erstes Argument zu verwenden.

Posix-Datenbank

Da es in POSIX-Shells keine regulären Ausdrücke gibt und die einzige Möglichkeit zum Testen eine Case-Anweisung ist, müssen wir eine Case-Anweisung verwenden. Leider müssen wir bei älteren Shells ([keine erweiterten Globs verfügbar][1]) eine Schleife ausführen, um alle Tests durchzuführen. Und die Globs müssen sein:

'aa*' 'abc*' '3@3*' '*>*'

Ein Skriptbeispiel, das mehrere Eingabezeichenfolgen anhand mehrerer Globs testet:

check_func() { :
           matched=1
       value=$1; shift
           for t in "$@"; do
               case $value in $t) matched=0; #break;; esac
                  echo "matched $value with $t"
                  ;;
       esac
       done
           return "$matched"
         }


for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
        echo "========A match was found for \"$var\""
fi
done

Eine einfachere Version der Funktion, die genau Ihrer Anfrage entspricht:

check_func() { :
               matched=1
               value=$1; shift
                   for t in "$@"; do
                       case $value in $t) matched=0; break;; esac
                   done
               return "$matched"
             }

Antwort3

Die Anweisung bewirkt Folgendes case: Sie übernimmt den zweiten Parameter der Funktion ( $2). Wenn dieser mit dem Muster übereinstimmt "$1"*, also dem ersten Argument der Funktion, gefolgt von irgendetwas, wird truedie Anweisung ausgeführt und beendet case. trueDies geschieht nichts und gibt den Status 0 zurück. Andernfalls, wenn es übereinstimmt *, also mit irgendetwas, wird falsedie caseAnweisung ausgeführt und beendet. Dies falsegeschieht nichts und gibt den Status 1 zurück. Somit hat die caseAnweisung den Status 0, wenn der zweite Parameter mit dem ersten Parameter beginnt, und andernfalls 1. Da dies die letzte (und einzige) Anweisung in der Funktion ist, gibt die Funktion 0 zurück, wenn der zweite Parameter mit dem ersten Parameter beginnt, und andernfalls 1.

Bedingte Anweisungen wie ifin der Shell betrachten eine Anweisung als wahr, wenn sie 0 zurückgibt, und andernfalls als falsch. Wird daher if beginswith "$var" "string"; then echo yes; else echo no; figedruckt yes, wenn der Wert varmit beginnt, stringund noandernfalls.

Es gibt mehrere alternative Möglichkeiten, diese Funktion zu schreiben. Beispielsweise hätte der Autor return 0oder return 1anstelle von trueund verwenden können false, da diese die letzte Anweisung in der Funktion sind. Die Art und Weise, wie die Funktion geschrieben wurde, ermöglicht es, ihren Hauptteil direkt zu verwenden, ohne ihn in eine Funktion einzuschließen, indem einfach die Verweise auf die Funktionsparameter ( $1und $2) in die Zeichenfolgen geändert werden, mit denen Sie arbeiten möchten.

Um mehrere Präfixe zuzulassen, durchlaufen Sie sie in einer Schleife. Sobald Sie ein passendes Präfix gefunden haben, kehren Sie mit dem Status „true“ (0) aus der Funktion zurück. Wenn keines der Präfixe übereinstimmt, geben Sie den Status „false“ (üblicherweise 1) zurück.

# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
  string=$1
  shift
  for prefix in "$@"; do
    case "$string" in
      "$prefix"*) return 0;;
    esac
  done
  return 1
}

if begins_with "$var" 'aa' 'abc' '3@3'; then
  echo "The value starts with one of the permitted prefixes"
fi

Um auf ein Suffix zu testen, verwenden Sie das Muster *"$suffix"anstelle von "$prefix"*. Um auf eine Teilzeichenfolge zu testen, verwenden Sie *"$substring"*. Beachten Sie, dass die Anführungszeichen hier erforderlich sind, da die Variable sonst als Muster interpretiert würde. Beispiel:

suffix='?'
case "$var" in
  *"$suffix") echo "The value of var ends with a question mark";; 
esac
case "$var" in
  *$suffix) echo "The value of var is not empty";; 
esac

Antwort4

Überarbeitet aufgrund der Klarstellung der Frage: Dies ist weniger elegant (und viel weniger flexibel), aber kompakter als die anderen Antworten.

check_func() {
        case "$1" in
            ( aa* | abc* | 3@3*  | *">"*)
                return 0
        esac
        return 1
}

Dies gibt true für aardvark, abcdef, [email protected]und zurück 12>5. Und natürlich auch für aard>vark, abc<def>ghiund 3@3>3.

verwandte Informationen