编写一个函数来检查字符串是否以某些内容开头或包含某些内容

编写一个函数来检查字符串是否以某些内容开头或包含某些内容

我想编写一个函数来检查给定变量(例如 )是否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。否则,如果匹配*,即任何内容,则执行false并结束该case语句。false不执行任何操作并返回状态 1。因此,case如果第二个参数以第一个参数开头,则该语句的状态为 0,否则为 1。由于这是函数中的最后一个(也是唯一一个)语句,因此如果第二个参数以第一个参数开头,则函数返回 0,否则返回 1。

条件语句(例如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

相关内容