Bash posix正規表現オプショングループ

Bash posix正規表現オプショングループ

カテゴリ/名前バージョン形式の文字列で、コンポーネントという名前の一部のGentooパッケージを一致させる試みの複雑さのため、次の結論に達しました。

if [[ "$1" =~ ^([<>]?=?)(([^\/]+)\/)?([^[:space:]]+)-(([[:digit:]]+)?(\.([[:digit:]]+))*([a-z])?(_(alpha|beta|pre|rc|p)([[:digit:]]*))*(-(r([[:digit:]]+))?)?)?$ ]]; then
    # use "${BASH_REMATCH[n]}" here to capture groups contents
fi

期待どおりに文字列を分割します<category/package-name-12345.25b_rc10-r7

Version specifier: <
Category: category
Package name: package-name
Version: 12345.25b_rc10-r7
Version, major: 12345
Version, minor: 25
Version, letter: b
Version, patch type: rc
Version, patch level: 10
Version, revision number: 7

これで、バージョンが欠落している可能性がある文字列を一致させて分割する必要がありますcategory/package-name

それでは、上記のバージョン部分をオプションにする方法はありませんか?

上記では、この部分は次のとおりです。

-(([[:digit:]]+)?(\.([[:digit:]]+))*([a-z])?(_(alpha|beta|pre|rc|p)([[:digit:]]*))*(-(r([[:digit:]]+))?)?)?

私はそれを次のように変更しようとしました。

(-(([[:digit:]]+)?(\.([[:digit:]]+))*([a-z])?(_(alpha|beta|pre|rc|p)([[:digit:]]*))*(-(r([[:digit:]]+)))?))?

バージョンのない文字列に対しては機能しますが、オプションのグループのため、上記のように少し完全な文字列と一致しないようです。

Version specifier: 
Category: category
Package name: package-name-12345.25b_rc10-r7
Version: 
Version, major: 
Version, minor: 
Version, letter: 
Version, patch type: 
Version, patch level: 
Version, revision number:

編集する:スロットマシン

オプション部品2個はいかがですか?

上記に加えて、スロットは一致する必要があります。スロットは次のように一致します。

:(([[:digit:]]+)(\.([[:digit:]]+))*)?

今、カテゴリ/名前の部分があります。

([<>]?=?)(([^\/]+)\/)?([^[:space:]]+)

次のいずれかのバージョンがあります。 -(([[:digit:]]+)(\.([[:digit:]]+))*)([a-z])?(_(alpha|beta|pre|rc|p)([[:digit:]]*))*(-(r([[:digit:]]+))?)?

スロット :(([[:digit:]]+)(\.([[:digit:]]+))*)?

または、バージョンとスロットの両方を適切な順序で選択します。

-バージョンは区切り文字で始まり、スロットは:区切り文字で始まります。

私が考えることができるものは:

if [[ "$1" =~ ^${CATEGORY_PACKAGE}-${VERSION}:${SLOT}$ ]] ; then
    # use "${BASH_REMATCH[n]}" here to capture groups contents
else
    if [[ "$1" =~ ^${CATEGORY_PACKAGE}:${SLOT}$ ]] ; then
        # use "${BASH_REMATCH[n]}" here to capture groups contents
    else
        if [[ "$1" =~ ^${CATEGORY_PACKAGE}-${VERSION}$ ]] || [[ "$1" =~ ^${CATEGORY_PACKAGE}$ ]] ; then
        # use "${BASH_REMATCH[n]}" here to capture groups contents
        fi
    fi
fi

これは完全な解決策ですか?より良いバージョンがありますか?たとえば、オプションベースのPOSIXソリューションはありますか<category-name>(<slot option>|<version option>|<version:slot> option)

編集する:

([^[:space:]:]+)bashが式でオプションのグループを処理できると思いましたが、それを処理するように変更することはできませんhyphenhyphen範囲の最初または最後にはできないようですが、どのように含めるべきですか?

答え1

IMOでは、可能なすべてのケースを単一の正規表現にまとめるよりも、この場合は複数の正規表現を使用する方が良いです。

base_package_name_regex='^([<>]?=?)(([^/]+)/)?([^[:space:]]+)'
version_regex='(([[:digit:]]+)?(\.([[:digit:]]+))*([a-z])?(_(alpha|beta|pre|rc|p)([[:digit:]]*))*(-(r([[:digit:]]+))?)?)?$ '
if [[ "$1" =~ $base_package_name_regex-$version_regex ]] || # package with version number
    [[ "$1" =~ $base_package_name_regex ]]  #  package without version number

then
    # use "${BASH_REMATCH[n]}" here to capture groups contents
fi

また、POSIX EREでは一致\/は指定されず、[^\/]バックスラッシュやスラッシュを除くすべての文字と一致します。私はその偽のバックスラッシュを削除しました。

答え2

シェルを使用する必要がある場合に切り替えることができますzsh。その後、POSIX EREの代わりにPCREを使用できます。

  • 最後まですべてを食い尽くし、バージョンが一致する可能性を残さず、ここで必要な貪欲でない演算子を得ることができます[^[:space:]]+(PCREでこれを短縮し、\S+貪欲でない変形に変更することができます)。\S+?
  • 正規表現をより明確にすることができます(?x)
  • キャプチャする必要がある部分だけをキャプチャします((?: ...)非キャプチャグループの場合)。
set -o rematchpcre
field_names=(
  version_specifier
  category
  package
  version
  major
  minor
  letter
  patch_type
  patch_level
  revision
)

typeset -A fields

if [[ $1 =~ '(?x)
  ^
  (?<version_specifier> [<>]? =? )
  (?: (?<category> [^/]+ ) / )?
  (?<package> \S+? )
  (?:
    -
    (?<version>
      (?<major> \d* )
      (?: \. (?<minor> \d+ ) )*
      (?<letter> [a-z] )?
      (?:
    _(?<patch_type> alpha|beta|pre|rc|p )
    (?<patch_level> \d* )
      )*
      (?: - (?: r (?<revision> \d+ ) )? )?
    )?
  )?
  \z' ]]; then
  fields=( "${(@)field_names:^match}" )
  typeset -p fields
fi

ここではキャプチャグループの名前を指定します(?<name> ...)が、これは文書化の目的でのみ使用され、キャプチャグループは単純な配列に格納され、zshはofと同じ名前で検索することを$matchサポートしていません。%+{name}perl

このスクリプトは以下を提供します。

$ ./that-script '<category/package-name-12345.25b_rc10-r7'
typeset -A fields=(
 [category]=category
 [letter]=b
 [major]=12345
 [minor]=25
 [package]=package-name
 [patch_level]=10
 [patch_type]=rc
 [revision]=7
 [version]=12345.25b_rc10-r7
 [version_specifier]='<'
)
$ ./that-script '<category/package-name'
typeset -A fields=(
 [category]=category
 [package]=package-name
 [version_specifier]='<'
)
$ ./that-script package-name
typeset -A fields=(
 [category]=''
 [package]=package-name
 [version_specifier]=''
)

関連情報