web-dev-qa-db-ja.com

文字列が何かで始まるか、または何かを含むかどうかをチェックする関数を記述します

与えられた変数、たとえばvarが、与えられた文字列のリスト内のいずれかの単語で始まるかどうかをチェックする関数を書きたいのですが。このリストは変更されません。

インスタンス化するために、varaaabcまたは3@3で始まるかどうかを確認したいとします。

さらに、var>という文字が含まれているかどうかを確認したいと思います。

この関数の名前をcheck_funcとしましょう。私の意図した使用法は次のようになります

if check_func "$var"; then
    do stuff
fi

たとえば、aardvarkabcdef[email protected]、および12>5は「何かを行う」必要があります。


私は this SO question を見てきましたが、ユーザーが作業の一部を提供しています:

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

私の考えは、上記のリストを繰り返し処理し、この関数を使用することです。私の難しさは、この作業を行うために終了(または終了を置き換えるもの)を行う方法を正確に理解していないことにあります。

6
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

テストを2つの機能に分けました。どちらもcase ... esacそして、これが決定されるとすぐに成功(ゼロ)を返します。何も一致しない場合、失敗(1)が返されます。

プレフィックスのリストをより動的なリストにするには、最初の関数を次のように書くことができます

check_prefixes () {
    value=$1
    shift

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

    return 1
}

(検査する値は最初の引数であり、関数の引数のリストからvalueに保存し、次にshiftに保存します。次に、残りの引数を反復処理します)、次のように呼び出します。

check_prefixes "$var" aa abc 3@3

2番目の関数は、同様の方法で次のように変更できます。

check_contains () {
    value=$1
    shift

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

    return 1
}

(いくつかの任意の部分文字列をチェックするため)、または

check_contains_oneof () {
    value=$1
    shift

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

    return 1
}

(いくつかの部分文字列のいずれかをチェックするため)

10
Kusalananda

Bashの場合:

正規表現のプロパティを使用すると、start^およびcontainで何も記述せずに済みます。

チェックする正規表現のリストstartaaabcまたは3@3およびcontains>は:

^aa ^abc ^3@3 >

適切に引用符で囲まれたリストを作成し、正規表現(=~)を使用するようbashに要求します。

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

関数は、一致のリストと変数の名前をハードコーディングしました。

配列変数の正規表現のリストと最初の引数でテストする値を与える:

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

関数をさらに改善して、(値の代わりに)変数の名前を最初の引数として使用できます。

posix

Posixシェルには正規表現がなく、テストする唯一の方法はcaseステートメントであるため、caseステートメントを使用する必要があります。悲しいことに、古いシェル([利用可能な拡張グロブなし] [1])の場合、すべてのテストを行うためにループする必要があります。そして、グロブは次のようにする必要があります:

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

複数のグロブに対して複数の入力文字列をテストするスクリプトの例:

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

リクエストに完全に一致する関数の単純なバージョン:

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

caseステートメントの機能は次のとおりです。関数の2番目のパラメーター($2)を取ります。パターン"$1"*に一致する場合、つまり、関数の最初の引数の後に何かが続く場合は、trueを実行してcaseステートメントを終了します。 trueは何もせず、ステータス0を返します。それ以外の場合、*、つまり何でも一致する場合は、falseを実行してcaseステートメントを終了します。 falseは何もせず、ステータス1を返します。したがって、caseステートメントのステータスは、2番目のパラメーターが最初のパラメーターで始まる場合は0、それ以外の場合は1です。これは関数の最後の(そして唯一の)ステートメントなので、2番目のパラメーターが最初のパラメーターで始まる場合、関数は0を返し、それ以外の場合は1を返します。

シェルのifなどの条件付きステートメントは、0を返す場合はステートメントをtrueと見なし、それ以外の場合はfalseと見なします。したがって、yesの値がvarで始まる場合はif beginswith "$var" "string"; then echo yes; else echo no; fistringを出力し、それ以外の場合はnoを出力します。

この関数を書くにはいくつかの方法があります。たとえば、作成者はtruefalseの代わりにreturn 0またはreturn 1を使用できます。これらは関数の最後のステートメントだからです。関数の記述方法では、関数パラメーター($1および$2)への参照を、操作する文字列に変更するだけで、関数にラップせずに本体を直接使用できます。 。

複数のプレフィックスを許可するには、それらをループで繰り返します。一致するプレフィックスが見つかったら、真のステータス(0)で関数から戻ります。一致するプレフィックスがない場合は、偽のステータス(通常は1)を返します。

# 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

サフィックスをテストするには、*"$suffix"ではなく"$prefix"*のパターンを使用します。サブストリングをテストするには、*"$substring"*を使用します。ここでは二重引用符が必要であることに注意してください。そうでない場合、変数はパターンとして解釈されます。例えば:

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

質問の明確化に基づいて改訂:これはエレガントではありません(そして柔軟性がはるかに低くなります)が、他の回答よりコンパクトです、

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

これは、aardvarkabcdef[email protected]および12>5に対してtrueを返します。そしてもちろん、aard>varkabc<def>ghi3@3>3も含まれます。