web-dev-qa-db-ja.com

Bash正規表現キャプチャグループ

文字列から複数の英数字の値(この数値は異なる場合があります)を照合し、それらをbashキャプチャグループ配列に保存しようとしています。ただし、私は最初の一致のみを取得しています。

mystring1='<link rel="self" href="/api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/api/clouds/1/instances/2AAAAAAA"/>'

regex='/instances/([A-Z0-9]+)'

[[ $mystring1 =~ $regex ]]

echo ${BASH_REMATCH[1]}
1BBBBBB

echo ${BASH_REMATCH[2]}

ご覧のように、それは私が探している最初の値と一致しますが、2番目の値とは一致しません。

23
Arthur Lyssenko

Bashでグローバルマッチングを実行できないのは残念です。あなたはこれを行うことができます:

global_rematch() { 
    local s=$1 regex=$2 
    while [[ $s =~ $regex ]]; do 
        echo "${BASH_REMATCH[1]}"
        s=${s#*"${BASH_REMATCH[1]}"}
    done
}
global_rematch "$mystring1" "$regex" 
1BBBBBB
2AAAAAAA

これは、一致するプレフィックスを文字列から切り取ることで機能し、次の部分を一致させることができます。それは文字列を破壊しますが、関数ではローカル変数なので、誰も気にしません。

私は実際にその関数を使用して配列を作成します:

$ mapfile -t matches < <( global_rematch "$mystring1" "$regex" )
$ printf "%s\n" "${matches[@]}"
1BBBBBB
2AAAAAAA
26
glenn jackman

2番目の配列値を取得するには、正規表現に2番目の括弧のセットが必要です。

mystring1='<link rel="self" href="/api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/api/clouds/1/instances/2AAAAAAA"/>'

regex='/instances/([A-Z0-9]+).*/instances/([A-Z0-9]+)'

[[ $mystring1 =~ $regex ]]

$ echo ${BASH_REMATCH[1]}
1BBBBBB
$ echo ${BASH_REMATCH[2]}
2AAAAAAA
7
Jeff Schaller

Pythonの実装:

def getall(mysentence):
    regex = re.compile(r'.*?/instances/([0-9A-Z]+)')
    result = regex.findall(mysentence)
    return result

print(getall('<link rel="self" href="/api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/api/clouds/1/instances/2AAAAAAA"/>'))
0