87967


pythonの正規表現について質問です。正規表現で、|を用いてマッチを行なったのですが、意図しないNoneが出力されてしまいます。どなたか、理由をご教授いただけますと幸いです。

**現状のコード**

[code]

    pattern = r"b(\d)|a(\d)"
    sentence = "a4"
    
    result = re.match(pattern, sentence)
    if result:
        print(result.group())
        print(result.group(1))
    
[/code]

**意図する出力**

[code]

    a4
    4
    
[/code]

**実際の出力**

[code]

    a4
    None
    
[/code]

**環境**

[code]

    python3 --version
    -Python 3.7.3
    
[/code]


CC BY-SA 4.0
2022-03-22T20:35:53.537
87966
2022-03-23T23:06:57.590
2022-03-22T22:25:33.827
4236
51915
question
python 正規表現
python 正規表現で和集合 | を使用した場合の group() で想定した出力が得られない


正規表現のグループ番号は、パターン文字列の内容に関わらず、`(`が登場する順に1から割り振られます。  
そのため、 `b(\d)|a(\d)` というパターンであれば

  * `b(\d)`側の`(\d)`が1
  * `a(\d)`側の`(\d)`が2

と割り振られます。このことを踏まえると次のような結果になるはずです。

  * `"a4"`の場合 
    * マッチ全体 `a4`
    * グループ1 `None`
    * グループ2 `4`
  * `"b5"`の場合 
    * マッチ全体 `b5`
    * グループ1 `5`
    * グループ2 `None`

* * *

以下はPythonには適用されません。

一部の正規表現エンジンは名前付きグループを定義できます。更に複数の名前付きグループを統合する機能を持つものもあります。例えば[.NETの正規表現](https://docs.microsoft.com/ja-
jp/dotnet/standard/base-types/grouping-constructs-in-regular-
expressions#named_matched_subexpression)では次のようにでき、名前付きグループ `num` で参照できます。

[code]

    b(?<num>\d)|a(?<num>\d)
    
[/code]

  * `"a4"`の場合 
    * マッチ全体 `a4`
    * グループnum `4`
  * `"b5"`の場合 
    * マッチ全体 `b5`
    * グループnum `5`

[Pythonは名前付きグループを定義できますが、グループは統合できない](https://docs.python.org/ja/3/library/re.html#index-17)ようです。


CC BY-SA 4.0
2022-03-22T22:25:17.297
87967
2022-03-23T23:06:57.590
2022-03-23T23:06:57.590
4236
4236
87966
answer


公式ドキュメントから:

[Regular Expression HOWTO -
Grouping](https://docs.python.org/3.10/howto/regex.html#grouping)

> **Groups are numbered starting with 0. Group 0 is always present; it’s the
> whole RE** , so match object methods all have group 0 as their default
> argument.

> **Subgroups are numbered from left to right, from 1 upward**. Groups can be
> nested; to determine the number, just count the opening parenthesis
> characters, going from left to right.
[code]

    import re
    
    pattern = r"b(\d)|a(\d)"
    sentence = "a4"
    
    result = re.match(pattern, sentence)
    if result:
        print(result.group(0))
        print(result.group(1, 2))
    
    #
    a4
    (None, '4')
    
[/code]

蛇足ながら、今回の場合は以下の様にしてもよいかと思います。

[code]

    import re
    
    pattern = r"[ab](\d)"
    sentence = "a4"
    
    result = re.match(pattern, sentence)
    if result:
        print(result.group())
        print(result.group(1))
    
[/code]

ちなみに [regex · PyPI](https://pypi.org/project/regex/) では同名の named group で
capture が可能です。

[code]

    import regex as re
    
    pattern = r"b(?P<num>(\d))|a(?P<num>(\d))"
    sentence = "a4"
    
    result = re.match(pattern, sentence)
    if result:
        print(result.group())
        print(result.group('num'))
    
    #
    a4
    4
    
[/code]


CC BY-SA 4.0
2022-03-22T23:14:43.160
87969
2022-03-22T23:39:59.690
2022-03-22T23:39:59.690
47127
47127
87966
answer