LoginSignup
12
3

More than 1 year has passed since last update.

Elixirの文字列はUTF-8だけど、RegexはUTF-8ではない

Last updated at Posted at 2023-02-04

はじめに|Elixirの文字列はUTF-8なバイナリである

Elixirの文字列はバイナリ。文字エンコーディングは、UTF-8。
ここまでは、駆け出しのアルケミスト(私を含む)だって知っている。
Elixir Schoolにもそう書いてある。

$ elixir -e 'IO.puts "本日は晴天なり"' | nkf --guess
UTF-8 (LF)
$

しかし、である。

問題点|Elixirの正規表現はUTF-8ではない

以下を実行して欲しい。

iex> String.match?("覚", ~r/[:]/)
true
iex>

は?! 「覚」に全角の「:」がマッチする? んなわけあるかーい!

原因

こーゆー事のようです。

iex> <<0>> <> "覚"
<<0, 232, 166, 154>>
iex> <<0>> <> ":"
<<0, 239, 188, 154>>
iex>

3バイト目の154(0x9A)が両文字に共通している。
つまり、

iex> <<0xE8, 0xA6, 0x9A>>
"覚"
iex> String.match?("覚", ~r/[\xE8\xA6\x9A]/)
true
iex> String.match?("覚", ~r/[\x9A]/)
true
iex>

「覚」も全角の「:」も、一つの文字として認識されておらず、1バイトづつバラバラの文字からなる文字列と認識されている様だ。
つまり、ElixirのRegexは、UTF-8ではない!

解決策|Unicodeをサポートする修飾子を付ける

正規表現を生成するシギル~rに、修飾子uを付けると、期待通りに動作する。

iex> String.match?("覚", ~r/[:]/u)
false
iex> String.match?(":", ~r/[:]/u)
true
iex>

感想

日本語を含むUnicode文字列を扱うとき人がハマりやすいハマりどころだと思い、この記事を書いてみました。

いやしかし、ElixirのRegexドキュメントにそんなこと書いてないやん。

:unicode (u) - enables Unicode specific patterns like \p and causes character classes like \w, \W, \s, and the like to also match on Unicode (see examples below in "Character classes"). It expects valid Unicode strings to be given on match

Unicodeに対応した文字クラスが使えるようになるよ、って意味でしょ、これ。
むしろ、この修飾子を付けないと、UTF-8を扱えない、US-ASCIIとして扱われる、と書くべきではないか。

てか、Elixirの文字列はUTF-8のバイナリと言ってるんだから、u修飾子をデフォルトにするべきではないか。

Issues書くかな…
プルリクの方が…

実行環境

この記事は、以下の環境で検証しました。

環境
 $ iex --version
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

IEx 1.14.3 (compiled with Erlang/OTP 25)
$

追記

関係しそうなIssuesの中にを発見。
https://github.com/elixir-lang/elixir/issues/3711
Joséは以下のように回答している。

Regex works on bytes by default so the second one is probably matching by accident due to the bytes involved. If you are using \p and friends, you likely want to use the u modifier:

つまり、Regexはデフォルトではバイト単位で動くよ、と。マルチバイトでは動かないよ、と。
こう認識されているのなら、Regexのドキュメントを修正すべきなんじゃないかなぁ。

12
3
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
12
3