Напишите функцию, которая проверяет, начинается ли строка с чего-либо или содержит ли что-либо

Напишите функцию, которая проверяет, начинается ли строка с чего-либо или содержит ли что-либо

Я хочу написать функцию, которая проверяет, varначинается ли заданная переменная, скажем, с любого слова из заданного списка строк. Этот список не изменится.

Для примера представим, что я хочу проверить, varначинается ли строка с aa, abcили 3@3.

Более того, я хочу проверить, varсодержит ли символ >.

Допустим, эта функция называется check_func. Мое предполагаемое использование выглядит примерно так:

if check_func "$var"; then
    do stuff
fi

Например, он должен «делать вещи» для aardvark, abcdefи .[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

Для Баша:

Используя свойства регулярных выражений, вы можете писать startс помощью ничего ^и containбез ничего.

Список регулярных выражений для проверкиначинатьс aa abcили 3@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 нет регулярных выражений, а единственный способ проверки — это оператор case, мы должны использовать оператор case. К сожалению, для старых оболочек ([расширенные globs недоступны][1]) мы должны зацикливаться, чтобы выполнить все проверки. И globs должны быть:

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

решение3

Вот что caseделает оператор: принимает второй параметр функции ( $2). Если он соответствует шаблону "$1"*, то есть первый аргумент функции, за которым следует что-либо, то выполнить trueи завершить caseоператор. trueничего не делает и возвращает статус 0. В противном случае, если он соответствует *, то есть что-либо, то выполнить falseи завершить caseоператор. falseничего не делает и возвращает статус 1. Таким образом, caseоператор имеет статус 0, если второй параметр начинается с первого параметра, и 1 в противном случае. Поскольку это последний (и единственный) оператор в функции, функция возвращает 0, если второй параметр начинается с первого параметра, и 1 в противном случае.

Условные операторы, такие как ifв оболочке, считают оператор истинным, если он возвращает 0, и ложным в противном случае. Следовательно, if beginswith "$var" "string"; then echo yes; else echo no; fiпечатает yes, если значение varначинается с, stringа noв противном случае.

Есть несколько альтернативных способов написать эту функцию. Например, автор мог бы использовать return 0or return 1вместо trueand false, так как они являются последним оператором в функции. Способ написания функции позволяет использовать ее тело напрямую, не оборачивая его в функцию, просто заменив ссылки на параметры функции ( $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

решение4

Пересмотрено на основе разъяснения вопроса: Это менее элегантно (и гораздо менее гибко), но более компактно, чем другие ответы.

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

Это возвращает true для aardvark, abcdef, [email protected]и 12>5. И, конечно же, также aard>vark, abc<def>ghiи 3@3>3.

Связанный контент