카테고리/이름 버전 형식의 문자열에서 구성 요소라는 이름의 일부 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가 표현식에서 선택적 그룹을 처리할 수 있다고 생각했지만 이를 처리하도록 변경할 수는 없습니다 hyphen
. hyphen
범위의 첫 번째나 마지막이 될 수 없는 것 같으니 어떻게 포함해야 할까요?
답변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]=''
)