文字列に大文字1個、小文字1個、数字1個、句読点1個以上が含まれているかどうかを確認するには?

文字列に大文字1個、小文字1個、数字1個、句読点1個以上が含まれているかどうかを確認するには?

これが私が今作業を完了するために使用しているものです:

#!/bin/sh --

string='Aa1!z'

if ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:upper:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:lower:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:digit:]]' || \
   ! printf '%s\n' "$string" | LC_ALL=C grep -q '[[:punct:]]'; then
  printf '%s\n' 'String does not meet your requirements'
else
  printf '%s\n' 'String meets your requirements'
fi

これは非常に非効率的で冗長です。もっと良い方法がありますか?

ベストアンサー1

1回の呼び出しでawkパイプなしで:

#! /bin/sh -
string='whatever'

has_char_of_each_class() {
  LC_ALL=C awk -- '
    BEGIN {
      for (i = 2; i < ARGC; i++)
        if (ARGV[1] !~ "[[:" ARGV[i] ":]]") exit 1
    }' "$@"
}

if has_char_of_each_class "$string" lower upper digit punct; then
  echo OK
else
  echo not OK
fi

これは POSIX ですが、mawkPOSIX 文字クラスはまだサポートされていません。--POSIX互換sには必要ありませんが、awk以前のバージョンのbusyboxには必要です(awksで始まる値をブロックします)。$string-

シェル構成を使用するこの関数の変形case

has_char_of_each_class() {
  input=$1; shift
  for class do
    case $input in
      (*[[:$class:]]*) ;;
      (*) return 1;;
    esac
  done
}

しかし、スクリプト中にシェルのロケールを変更することがすべてのsh実装で機能するわけではありません。したがって、入力をCロケールでエンコードされたものとして扱うには、Cロケールでスクリプトを呼び出す必要があります。 C ロケール文字セットと文字クラスは、POSIX 指定文字セットと文字クラスにのみ一致します。

おすすめ記事