編寫一個函數來檢查字串是否以某些內容開頭或包含某些內容

編寫一個函數來檢查字串是否以某些內容開頭或包含某些內容

我想編寫一個函數來檢查給定變數(例如 )是否var以給定字串列表中的任何單字開頭。這個清單不會改變。

為了實例化,讓我們假設我想檢查是否varaa,abc或開頭3@3

此外,我想檢查是否var包含字元>

假設這個函數被稱為check_func.我的預期用途看起來像

if check_func "$var"; then
    do stuff
fi

例如,它應該為 、 和aardvarkabcdef做一些事情” 。[email protected]12>5


我見過這個問題使用者提供部分工作的情況:

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

我的想法是我會迭代上面提到的列表並使用這個函數。我的困難在於不確切地理解應該如何退出(或任何替代返回的方式)才能完成這項工作。

答案1

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

我將測驗分為兩個功能。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

第二個函數可以以類似的方式更改為

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
}

(檢查多個子字串中的任何一個)

答案2

對於bash:

使用正規表示式的屬性,您可以不start使用^contain不使用任何內容進行編寫。

要檢查的正規表示式列表開始aa abc3@3包含 >是:

^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 shell 中沒有正規表示式,且唯一的測試方法是 case 語句,因此我們必須使用 case 語句。遺憾的是,對於較舊的 shell([沒有可用的擴充 glob][1]),我們必須循環進行所有測試。並且,glob 必須是:

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

針對多個 glob 測試多個輸入字串的腳本範例:

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"
             }

答案3

此語句的作用如下case:將第二個參數傳遞給函數 ( $2)。如果它與模式匹配"$1"*,即函數的第一個參數後面跟著任何內容,則執行true並結束該case語句。true不執行任何操作並傳回狀態0 *。不執行任何操作並傳回狀態 1 。由於這是函數中的最後一個(也是唯一一個)語句,因此如果第二個參數以第一個參數開頭,則函數傳回 0,否則傳回 1。falsecasefalsecase

條件語句(例如ifshell 中的條件語句)如果傳回 0,則認為語句為真,否則認為語句為假。因此,如果 的值以以下開頭,則列印,否則if beginswith "$var" "string"; then echo yes; else echo no; fi列印。yesvarstringno

有幾種替代方法可以編寫此函數。例如,作者可以使用return 0orreturn 1代替trueand false,因為它們是函數中的最後一個語句。函數的編寫方式使得可以直接使用其主體,而無需將其包裝在函數中,只需將對函數參數 ($1$2) 的引用更改為您想要使用的任何字串即可。

若要允許多個前綴,請在循環中迭代它們。一旦找到匹配的前綴,就會從函數傳回,狀態為 true (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

答案4

根據問題的澄清進行修改: 這不太優雅(也不太靈活),但比其他答案更緊湊,

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

aardvark對於、abcdef[email protected],這傳回 true 12>5。當然,還有aard>varkabc<def>ghi3@3>3

相關內容