$30 off During Our Annual Pro Sale. View Details »

POSIX文字クラスでの躓き

muryoimpl
August 27, 2023

 POSIX文字クラスでの躓き

Kanazawa.rb meetup#132 祝11周年 LT大会での LT。
Ruby (Onigmo) ではエンコーディングによって、POSIX文字クラス名の見た目と挙動に差が出ちゃうよ、という話。

muryoimpl

August 27, 2023
Tweet

More Decks by muryoimpl

Other Decks in Programming

Transcript

  1. POSIX文字クラスでの躓き
    2023/08/26 (Sat) Kanazawa.rb meetup#132
    muryoimpl

    View Slide

  2. ある日の irb にて
    ● 環境は、 ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
    ● 以下のコードを入力してみたが、イメージしていたものと違う動作をした。
    irb(main):001:0:> /[[:alnum:]]+/.match?(“10”)
    : true
    irb(main):002:0:> /[[:alnum:]]+/.match?(“あ0”)
    : true
    [[:alnum:]] で “あ” で true ? なぜ?から調査は始まった。

    View Slide

  3. ChatGPT さんに訊いてみたが……
    どうやら、私がおかしなことを
    言ってる感じですね

    View Slide

  4. まず「Ruby 正規表現」でググる

    View Slide

  5. View Slide

  6. 正規表現のページを確認すると
    ● [:alnum:] は POSIX 文字クラスまたはPOSIXブラケット というもの。
    また、[:^クラス名:]という記法でその否定を意味する。
    (以下、POSIXブラケットと呼ぶ)
    ● 似たような機能を持つ記法に Unicode プロパティというものもある。
    ○ \p{property-name}
    ○ \p{^property-name} (否定)
    ○ 具体例: \p{Letter}

    View Slide

  7. エンコーディングによって挙動が変わるらしい。
    詳しくは Onigmo のドキュメントを見ろとある。

    View Slide

  8. Onigmo のドキュメント(日本語版)を
    見る
    https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja

    View Slide

  9. View Slide

  10. View Slide

  11. Unicodeプロパティ
    ● Rubyのデフォルトエンコーディングは UTF-8
    irb(main):001:0:> "あ".encoding
    : #
    ● alnum は Unicodeプロパティの Letter | Mark | Decimal_Number に相当する。こ
    れは Ruby の正規表現のページにも同じ記載があった。
    ● Mark と Decimal_Number はぼんやりとイメージが湧くが、Letter の範囲は?
    ○ https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp にて、Unocodeプロパティを入力して範
    囲を確認してみる

    View Slide

  12. ブラウザでアクセスして確認する

    View Slide

  13. Unicodeプロパティ \p{Letter}
    ● ひらがな、漢字等かなりの広範囲の”文字”が含まれていた。
    ● Onigmo のドキュメントにあったとおり、エンコーディングが Unicode の場合におい
    て、 実はほとんどすべての文字をカバーしてしまう
    ● つまり、alnum は alphabet と number ではない。 Letter が alphabet のみなら
    ず、広範囲の文字をカバーしてしまうため
    ● 英数字のみならば、/ [a-zA-Z0-9]+/.match?(“あ”) みたいに、明示的に範囲を指定
    するか
    ● 正規表現のページのオプションによると、/(?a:[[:alnum:]]+)/.match?("あ") のよう
    に、オプションで動作が変えられるようだ

    View Slide

  14. d, u は、UnicodeではPOSIXブラケットは非ASCII文字にマッチしてしまう。
    a は、POSIXブラケットは非ASCII文字にマッチしないので、:alnum: は英数字にマッチする

    View Slide

  15. まとめ
    ● Rubyのデフォルトエンコーディングは UTF-8 、正規表現でPOSIXブラケットを見た
    ままのイメージで使うと痛い目に遭う
    ● Onigmo の POSIXブラケットはエンコーディングによって挙動が変わるため、使う場
    合は文字列のエンコーディングを意識する必要がある
    ● 正規表現のみならず、処理を実装するときは失敗パターンも確認しましょう
    ● ChatGPT さんの意見を鵜呑みにしてはいけない

    View Slide