Escribe una función que verifique si una cadena comienza con algo o contiene algo

Escribe una función que verifique si una cadena comienza con algo o contiene algo

Quiero escribir una función que verifique si una variable dada, digamos, varcomienza con alguna de las palabras en una lista determinada de cadenas. Esta lista no cambiará.

Para crear una instancia, supongamos que quiero comprobar si varcomienza aacon abco 3@3.

Además, quiero comprobar si varcontiene el carácter >.

Digamos que esta función se llama check_func. Mi uso previsto se parece a

if check_func "$var"; then
    do stuff
fi

Por ejemplo, debería "hacer cosas" para aardvark, abcdefy .[email protected]12>5


He vistoesta pregunta SOdonde un usuario proporciona parte del trabajo:

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

Mi idea es iterar sobre la lista mencionada anteriormente y usar esta función. Mi dificultad radica en no entender exactamente cómo se debe salir (o lo que sea que reemplace el regreso) para que esto funcione.

Respuesta1

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

Dividí las pruebas en dos funciones. Tanto el uso case ... esaccomo la devolución son exitosos (cero) tan pronto como se pueda determinar. Si nada coincide, se devuelve el error (1).

Para hacer que la lista de prefijos sea más dinámica, posiblemente se podría escribir la primera función como

check_prefixes () {
    value=$1
    shift

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

    return 1
}

(el valor a inspeccionar es el primer argumento, que guardamos dentro valuey luego shiftfuera de la lista de argumentos de la función; luego iteramos sobre los argumentos restantes) y luego lo llamamos como

check_prefixes "$var" aa abc 3@3

La segunda función podría cambiarse de manera similar, en

check_contains () {
    value=$1
    shift

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

    return 1
}

(para comprobar si hay alguna subcadena arbitraria), o

check_contains_oneof () {
    value=$1
    shift

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

    return 1
}

(para comprobar si hay alguna de varias subcadenas)

Respuesta2

Para fiesta:

Usando las propiedades de expresiones regulares puedes escribir startcon ^y containsin nada.

La lista de expresiones regulares para verificar.comenzarcon aa abco 3@3ycontiene >es:

^aa ^abc ^3@3 >

Haz de eso unadecuadamentelista citada y pedirle a bash que use expresiones regulares ( =~):

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

La función ha codificado la lista de coincidencias y el nombre de la var.

Proporcionando la lista de expresiones regulares en una variable de matriz y el valor a probar en el primer argumento:

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

La función podría mejorarse aún más para utilizar el nombre de una variable (en lugar de un valor) como primer argumento.

posix

Como no hay expresiones regulares en los shells posix y la única forma de realizar pruebas es una declaración de caso, debemos usar una declaración de caso. Lamentablemente, para shells más antiguos ([no hay globs extendidos disponibles][1]) debemos realizar un bucle para realizar todas las pruebas. Y los globos deben ser:

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

Un ejemplo de script que prueba varias cadenas de entrada con varios globos:

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

Una versión más simple de la función que se adapta exactamente a su solicitud:

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

Respuesta3

Esto es lo que casehace la declaración: llevar el segundo parámetro a la función ( $2). Si coincide con el patrón "$1"*, es decir, el primer argumento de la función seguido de cualquier cosa, ejecute truey finalice la casedeclaración. trueno hace nada y devuelve el estado 0. De lo contrario, si coincide *, es decir, cualquier cosa, ejecuta falsey finaliza la casedeclaración. falseno hace nada y devuelve el estado 1. Por lo tanto, la casedeclaración tiene el estado 0 si el segundo parámetro comienza con el primer parámetro y 1 en caso contrario. Dado que esta es la última (y única) declaración de la función, la función devuelve 0 si el segundo parámetro comienza con el primer parámetro y 1 en caso contrario.

Las declaraciones condicionales, como las ifdel shell, consideran que una declaración es verdadera si devuelve 0 y falsa en caso contrario. Por lo tanto, if beginswith "$var" "string"; then echo yes; else echo no; fise imprime yessi el valor de varcomienza con stringy noen caso contrario.

Hay varias formas alternativas de escribir esta función. Por ejemplo, el autor podría haber usado return 0o return 1en lugar de truey false, ya que son la última declaración de la función. La forma en que se escribió la función hace posible usar su cuerpo directamente sin envolverlo en una función, simplemente cambiando las referencias a los parámetros de la función ( $1y $2) a cualquier cadena con la que desee trabajar.

Para permitir múltiples prefijos, repita sobre ellos en un bucle. Tan pronto como haya encontrado un prefijo coincidente, regrese de la función con un estado verdadero (0). Si ninguno de los prefijos coincide, devuelve un estado falso (convencionalmente 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

Para probar un sufijo, use el patrón *"$suffix"en lugar de "$prefix"*. Para probar una subcadena, use *"$substring"*. Tenga en cuenta que las comillas dobles son necesarias aquí; de lo contrario, la variable se interpretaría como un patrón. Por ejemplo:

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

Respuesta4

Revisado en base a la aclaración de la pregunta: Esto es menos elegante (y mucho menos flexible), pero más compacto que las otras respuestas.

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

Esto devuelve verdadero para aardvark, abcdefy . Y, por supuesto, también , y .[email protected]12>5aard>varkabc<def>ghi3@3>3

información relacionada