Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

0

Share

Download to read offline

Ruby の正規表現について

Download to read offline

大手町.rb #17 発表資料

Related Books

Free with a 30 day trial from Scribd

See all
  • Be the first to like this

Ruby の正規表現について

  1. 1. Ruby の 正規表現について 2019/05/15 大手町.rb #17
  2. 2. 大手町.rb #17 「Ruby の正規表現について」 1自己紹介 Tomoya Kawanishi a.k.a. @cuzic エネチェンジ株式会社 チーフエンジニア 電力会社、ガス会社を切り替えるなら、エネチェンジ経由で! 一般家庭も!法人も! Ruby関西の中の人 2019年7月13日(土) 第87回Ruby関西勉強会 2019年9月15日(日) 大阪RubyKaigi 02 発表者として登壇くださる方、あとで声かけください。 大手町.rb の中の人 毎月 大手町.rb の開催を予定 東京駅、各線大手町駅から直結! Ruby の初級者がメインターゲット
  3. 3. 大手町.rb #17 「Ruby の正規表現について」 今日のテーマ Ruby の正規表現について 正規表現という用語について 英語の Regular Expression の日本語訳 言語学では「正則表現」 expression は「表現」以外に「式」という意味もある 違和感があるが、いまさらどうしようもない 正規表現はなぜ重要か 正規表現を使うと 特定の文字列にマッチするかどうかの判定ができる 文字列の一部を取得(capture)することがカンタンにできる ログ処理、テキストバリデーションなどがカンタンにできる 特徴 ほぼすべての言語で実装されており、応用範囲が幅広い 非常にコンパクトに記述でき、可読性、メンテナンス性が高い 知る人ぞ知る機能も多いがベンリ 2
  4. 4. 大手町.rb #17 「Ruby の正規表現について」 正規表現の作り方 /hoge/ のように / で正規表現を作るのが一般的 中に / があるときは %r 記法を使う 正規表現にしたい文字列を引数で受け取るときなどは Regexp.new を使うこともある / や %r の中では 式展開 #{} を使うこともできる 3 /hoge/ : もっとも一般的 %r(https://enechange¥.jp) # % 記法。 Regexp.new("https://enechange¥¥.jp") # Regexp.new Regexp.compile("https://enechange¥¥.jp") # Regexp.compile production_domain = "enechange¥¥.jp" %r(https://#{production_domain})
  5. 5. 大手町.rb #17 「Ruby の正規表現について」 正規表現の例 正規表現を使うと、文字列マッチが簡単にできる ^ : アンカーの一つ。行頭にマッチする () : 正規表現の一部をキャプチャするときに使う . : メタ文字の1つ。改行を除く任意の1文字にマッチ + : メタ文字の1つ。直前の部分式を1回以上の繰り返し にマッチ 4 url = "https://enechange.jp/try/input" # / を使った正規表現リテラル。 マッチした position を返す。 url =~ /^https:¥/¥/enechange¥.jp/(.+)/ #=> 0 $1 #=> "try/input" # %r を使った正規表現リテラル url =~ %r(^https://enechange¥.jp/(.+)) # String#match? を使うと true false を返す url.match?(%r(¥Ahttps://enechange¥.jp/(.+)))
  6. 6. 大手町.rb #17 「Ruby の正規表現について」 正規表現visualizer Regulex という正規表現の visualizer がある。 慣れないうちは visualizer を使って、 その正規表現がどういう処理になるかを確認しながら、 進めると良い 5 # %r を使った正規表現リテラル url =~ %r(^https://enechange¥.jp/(.+))
  7. 7. 大手町.rb #17 「Ruby の正規表現について」 正規表現を学ぶときのコツ 正規表現は仕様が膨大 すべてを最初から理解して使いこなす必要はない 業務で必要になる都度、少しずつ理解している範囲を広 げるといい 正規表現の練習用サイトもある https://regexone.com/ https://www.hackerrank.com/domains/regex 正規表現マッチを簡単に確認できるサイトもある http://refiddle.com/ https://rubular.com/ いろいろ既存サービスを使いこなして、上達を目指しま しょう 6
  8. 8. 大手町.rb #17 「Ruby の正規表現について」 文字マッチ 7 . : 改行を除く任意の1文字 ¥から始まらない文字 a など : a にマッチ ¥n : 改行にマッチ ¥記号 ¥/ ¥. など : その記号1文字にマッチ ¥w : 単語構成文字。 英小文字、英大文字、数字、アンダースコア、a-zA-Z0-9_ ¥s : 空白文字。半角空白、タブ、改行、ほか [ ¥t¥r¥n¥f¥v] ¥d : 0から9 の数字 [abc] : 文字 a か b か c [0-3] : 文字、 0 1 2 3 にマッチ "2019-05-15".match?(/20¥d¥d-[01]¥d-[0-3]¥d/) "example@example.jp".match?(/[-.¥w]+@)[-.¥w]+¥.jp/)
  9. 9. 大手町.rb #17 「Ruby の正規表現について」 アンカー 8 ^ : 行頭にマッチ $ : 行末にマッチ ¥A : 文字列の先頭にマッチする ¥Z : 文字列の末尾にマッチ。ただし、改行が最後にあるときはその直前にマッチ。 ¥z : 文字列の末尾にマッチする。 ¥b : 単語の境界にマッチする body = File.read("/etc/passwd") body =~ /root/ #=> 0 body =~ /nobody/ #=> 818 body =~ /¥Aroot/ #=> 0 body =~ /¥Anobody/ #=> nil body =~ /bash$/ #=> 27 body =~ /bash¥Z/ #=> 2248 body =~ /bash¥z/ #=> nil アンカーとは 幅0 の文字列にマッチするメタ文字列
  10. 10. 大手町.rb #17 「Ruby の正規表現について」 繰り返し、量指定子 9 * : 0回以上 + : 1回以上 ? : 0回もしくは1回 {n} :ちょうどn回(nは数字) {n,} : n回以上(nは数字) {,m} : m回以下(mは数字) {n,m} : n回以上m回以下(n,mは数字) 直前の部分式を何回繰り返すかを指定する 欲張り(greedy)マッチ。最長の文字列にマッチする "2019-05-15".match?(/¥d{4}-¥d¥d?-¥d¥d?/) "2019-05-15".match?(/¥d{4}(-¥d{1,2}){2}/) # /¥d{4}-¥d{1,2}-¥d{1,2}/ と同じ。 '<a href="#">'.match?(/¥<a¥s+href='?"?#'?"?¥s*¥>/) m = '<div><a href="#">top</a></div>'.match(/<.+>/) m[0] #=> "<div><a href=¥"#¥">top</a></div>" m = /^.*(¥d+)¥./.match("Copyright 2013.") m[1] #=> 3
  11. 11. 大手町.rb #17 「Ruby の正規表現について」 最小量指定子 直前の部分式を何回繰り返すかを指定する 最短の文字列にマッチする 10 *? : 0回以上 +? : 1回以上 ?? : 0回もしくは1回 {n}? :ちょうどn回(nは数字) {n,}? : n回以上(nは数字) {,m}? : m回以下(mは数字) {n,m}? : n回以上m回以下(n,mは数字) m = '<div><a href="#">top</a></div>'.match(/¥<.+?¥>/) m[0] #=> "<div>" m = /^.*?(¥d+)¥./.match("Copyright 2013.") m[1] #=> 2013
  12. 12. 大手町.rb #17 「Ruby の正規表現について」 キャプチャ 丸括弧()で、キャプチャできる 11 regex = %r(¥<a href="(.+?)".*?>(.+?)</a>) m = '<div><a href="#">top</a></div>'.match(regex) m[1] #=> "#" m[2] #=> "top"
  13. 13. 大手町.rb #17 「Ruby の正規表現について」 いずれかへのマッチ 縦棒(パイプ) | で、複数の正規表現のどれかにマッ チするかどうかという判定ができる 凝った正規表現を書くよりは、 | で分割する方が分かりやすいこともある 12 request.fullpath.match?(%r(¥A/(login|logout))) # "/login" や "/logout" 、 "/login?from=blahblah" などにマッチする message =~ /([0-9a-zA-Z]|[0-9a-zA-Z])+/
  14. 14. 大手町.rb #17 「Ruby の正規表現について」 正規表現関連のメソッド (String クラス) 13 # String#[regex] : 正規表現にマッチした文字列を返す "We are hiring"[/¥b¥w+$/] #=> "hiring" # String#[regex, index] : 正規表現にマッチし、その index のキャプチャ文字列を返す "We are hiring"[/.+¥b(¥w+)$/, 1] #=> "hiring" # String#=~ : 正規表現とマッチした position を返す "We are hiring" =~ /¥b(¥w+)$/ #=> 7 # String#match : 正規表現とマッチした MatchData オブジェクトを返す "We are hiring".match(/¥b(¥w+)$/) #=> #<MatchData "hiring" 1:"hiring"> body = File.read("/etc/passwd") index = body =~ /bash$/ body.match(/^.+bash$/, index) # index 文字目からサーチを開始する # String#match? : マッチ結果を true、 false で返す。動作が速い。 "We are hiring".match?(/¥b(¥w+)$/) #=> true String クラスで正規表現関連で特に有用なメソッドを 5つ紹介します
  15. 15. 大手町.rb #17 「Ruby の正規表現について」 正規表現関連のメソッド (Regexp クラス) 14 # Regexp.quote : 正規表現をエスケープする prod_url = "https://enechange.jp" /¥b#{prod_url}¥b/ =~ "https://enechangeejp" #=> 0 マッチする /¥b#{Regexp.quote(prod_url)}¥b/ =~ "https://enechangeejp" #=> nil。マッチしない。 # Regexp.union( pat1, pat2, …) : 引数のいずれかにマッチする正規表現を返す # 複雑な正規表現を段階的に構築したいときに便利 re_letter = Regexp.union(/[0-9a-zA-Z]/, /[0-9A-Za-z]/) message =~ /#{re_letter}+/ # Regexp#match、 Regexp#match? : String クラスの対応するメソッドと同じ Regexp クラスで正規表現関連で特に有用なメソッドを 3つ紹介します
  16. 16. 大手町.rb #17 「Ruby の正規表現について」 正規表現関連のメソッド (MatchData クラス) 15 body = File.read("/etc/passwd") m = body.match(/.+:(.+?sh)$/) # MatchData#captures で括弧 () でキャプチャした文字列を配列で取得できる m.captures #=> ["/bin/bash"] # MatchData#[] でマッチした文字列を配列のようにアクセスできる m[0] #=> "root:x:0:0:root:/root:/bin/bash" m[1] = "/bin/bash" m.pre_match #=> "" m.post_match #=> "¥ndaemon:…(snip)" # MatchData#begin(index) で index に対応する要素の開始位置が分かる m.begin(0) #=> 0 m.begin(1) #=> 22 # MatchData#end(index) で index に対応する要素の終了位置が分かる m.end(0) #=> 31 m.end(1) #=> 31 m2 = body.match(/.+:(.+?sh)$/, m.end(0)) m2.pre_match #=> "root:x…(snip)" m2.begin(0) #=> 1615
  17. 17. 大手町.rb #17 「Ruby の正規表現について」 今回扱わなかったトピック 正規表現はとても奥が深く、今回は時間の関係もあり、 省略した話題が数多くあります。 興味がある方は自分で調べてください。 後方参照 特殊変数($`、$'、$1、$2 など) 名前付きキャプチャ Unicodeプロパティ アトミックグループ 部分式呼び出し(subexpression call) 先読み、後読み 条件分岐 非包含オペレータ 16
  18. 18. 大手町.rb #17 「Ruby の正規表現について」 まとめ 正規表現は文字列へのマッチ、ログ処理等でとても役立つ 正規表現を使う上で特に利用頻度が高いものを中心に さまざまなノウハウを紹介 複雑な正規表現を作るときは 正規表現の visualizer ツールで、ロジックを確認したり refiddle などでマッチするかどうかを確認したり いきなり複雑な正規表現を作ろうとせず、段階的に構築しましょう Regexp.escape Regexp.union 正規表現の式展開 /#{regexp}/ 17
  19. 19. ご清聴ありがとう ございました

大手町.rb #17 発表資料

Views

Total views

1,383

On Slideshare

0

From embeds

0

Number of embeds

84

Actions

Downloads

2

Shares

0

Comments

0

Likes

0

×