演算子 ?: は、特に正規表現にグループが含まれている場合、Ruby 正規表現の ( () の直後に置かれた場合に何をしますか? [重複]

概要

string = "This is a paragraph with a bunch3c:77:e6:68:66:e9of random MAC addresses 1100:50:7F:E6:96:20hello world 15:00s, 00:50:56:c0:00:08 some other text is written here 00-0C-29-38-1D-61 00:11:22book.FF:DD:CC"
mac_regex = /(?:[0-9A-F]{2}[\:\-]){5}[0-9A-F]{2}/i
mac_addresses = string.scan(mac_regex)
print mac_addresses 

これは [“3c:77:e6:68:66:e9”, “00:50:7F:E6:96:20”, “00:50:56:c0:00:08”, “00-0C-” を返します29-38-1D-61”]。

mac_regex から ?: を削除すると、mac_regex = /([0-9A-F]{2}[:-]){5}[0-9A-F]{2}/i となり、print mac_addresses が返されます。 [[“66:”]、[“96:”]、[“00:”]、[“1D-”]]、つまり ([0-9A-F]{2}[:-] ){5} は、オクテットの 5 つすべてをまとめて照合するのではなく、オクテットの 5 番目に出現したもののみと一致します (私の理解では、5 つすべてをまとめて照合することになっていると考えられています)。

([0-9A-F]{2}[:-]){5} が 5 オクテットの文字列ではなく、5 番目のオクテットの一致に対応するのはなぜですか?そしてなぜ ?: が必要なのでしょうか、([0-9A-F]{2}[:-]){5} -> (?:[0-9A-F]{2}[:-]) {5}、5 オクテットの文字列の一致に対応させるには?

解決策

(?:…) は非キャプチャ グループです。 String#scan には 2 つの異なる動作があるため、これが使用されます。

このパターンにはグループが 1 つしかなく、キャプチャされていないため、スキャンは最初の動作を使用し、完全に一致したものだけを配列として返します。

?: を削除すると、2 番目の動作に切り替わり、その 1 つのグループのみが返されます。そして、繰り返し {5} はグループの外側にあるため、グループは 5 つすべてをまとめて参照するのではなく、各オクテットのみを参照することを意味します。したがって、キャプチャされたオクテットが最後に一致したオクテットになります。

?: を使用せずに同じ動作を実現するには、パターン全体に別のキャプチャ グループを追加し、結果からそのグループを抽出する必要があります。

mac_regex = /(([0-9A-F]{2}[\:\-]){5}[0-9A-F]{2})/i
mac_addresses = string.scan(mac_regex).map(&:first)