0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Ruby で正規表現の連結(連接、concatenation)

Posted at

本題に入る前に

Ruby では Regexp.union を使用すると正規表現のORによる結合を簡単に実現できます。
(ORによる結合には、「union」「和」「選択」「選言」などの呼び方もあります。)

union.rb
a = /[Ff]iz+/
b = /buz+/i
c = Regexp.union(a, b)

p 'fiz'.scan(c)      # => ["fiz"]
p 'BUZZZZ'.scan(c)   # => ["BUZZZZ"]
p 'FizzBuzz'.scan(c) # => ["Fizz", "Buzz"]

正規表現の連結 (concatenation)

では、あるパターンの後に別のパターンが続くような正規表現はどうでしょうか。
Ruby の正規表現には他の正規表現を埋め込むことができるそうなので、上記はこれにより実現できます。
(このような連結の操作は、「concatenation」「連接」などの呼び方もあります。)

concat.rb
a = /[Ff]iz+/
b = /buz+/i
c = /#{a}#{b}/

p 'Fizz'.scan(c)     # => []
p 'buzzFizz'.scan(c) # => []
p 'FizzBUZZ'.scan(c) # => ["FizzBUZZ"]

参考:

二重引用符の文字列リテラルと同様に、正規表現中でも変数展開が可能ですが、与えたものは#to_sで展開されます。
そして、Regexp#to_sでは、「返される文字列は他の正規表現に埋め込んでもその意味が保持されるようになっています」。

余談(AND演算について)

正規表現の基本の演算にはAND演算(正規言語の積集合を取る演算)は含まれておらず、簡単な表記でこれを実現することはできませんが、言語によっては肯定的先読みアサーションで実現できるようです。以下の例では /[Ff]iz+//buz+/i の両方に部分一致するかどうかを判定しています。

intersection.rb
a = /[Ff]iz+/
b = /buz+/i
c = /\A(?=.*#{a})(?=.*#{b}).*/

p c =~ 'Fizz'                 # => nil (マッチせず)
p c =~ 'BUZZ'                 # => nil (マッチせず)
p c =~ 'fizz BUZZ'            # => 0 (マッチ)
p c =~ '1 2 Fizz 4 Buzz Fizz' # => 0 (マッチ)

まとめ

# 正規表現の和
union = Regexp.union(a, b)
# または
union = /#{a}|#{b}/

# 正規表現の連接
concat = /#{a}#{b}/

# 正規表現の閉包(0回以上の繰り返し)
closure = /#{a}*/

# 正規表現の積(部分一致)
intersection = /\A(?=.*#{a})(?=.*#{b}).*/
# 正規表現の積(全体一致)
intersection = /(?=\A#{a}\z)(?=\A#{b}\z).*/

おわりに

同じ内容の記事がなさそうだったので書きました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?