Julia:関数split()と日本語文字列で困ったこと

技術
この記事は約5分で読めます。

はじめに

 文字列を分割する関数 split() ですが、日本語文字列を区切りなしで分割する際にちょっと困ったことがあったので、まとめておきます。

 まずは、関数 split() の挙動について整理しておきます。

区切りを指定して分割する

区切りに指定できるのは、文字、文字列、正規表現、関数などです。以下、例を示します。

ASCII文字が区切り
s = "2022/08/08"
split(s, '/')
3-element Vector{SubString{String}}:
 "2022"
 "08"
 "08"
マルチバイト文字(全角文字)が区切り
s = "2022-08-08"
split(s, '-')
3-element Vector{SubString{String}}:
 "2022"
 "08"
 "08"
ASCII文字列が区切り
s = "abcxyzdefxyzghi"
split(s, "xyz")
3-element Vector{SubString{String}}:
 "abc"
 "def"
 "ghi"
マルチバイト文字列が区切り
s = "abcxyzdefxyzghi"
split(s, "xyz")
3-element Vector{SubString{String}}:
 "abc"
 "def"
 "ghi"

区切りなしで分割

 ドキュメントによれば、区切りを省略すると、関数 isspace() が使われます。
 さらに isspace() のドキュメントによると次のように書かれています

Tests whether a character is any whitespace character. Includes ASCII characters ‘\t’, ‘\n’, ‘\v’, ‘\f’, ‘\r’, and ‘ ‘, Latin-1 character U+0085, and characters in Unicode category Zs.

文字が空白文字かどうかを判定します。空白文字とみなされるのは ASCII 文字 '\t''\n''\v''\f''\r'' ' およびラテン 1 文字 U+0085、そして Unicode カテゴリ Zs に含まれる文字です。

https://docs.julialang.org/en/v1/base/strings/#Base.Unicode.isspace

Unicode カテゴリ Zs とは Space_Separator のことで、次の文字が含まれています。

Space(SP)U+0020
No-Break Space(NBSP)U+00A0
Ogham Space MarkU+1680
En QuadU+2000
Em QuadU+2001
En SpaceU+2002
Em SpaceU+2003
Three-PerEm SpaceU+2004
Four-Per-Em SpaceU+2005
Six-Per-Em SpaceU+2006
Figure SpaceU+2007
Punctuation SpaceU+2008
Thin SpaceU+2009
Hair SpaceU+200A
Narrow No-Break Space(NNBSK)U+202F
Medium Mathematical Space(MMSP)U+205F
Ideographic SpaceU+3000
ASCII文字列が区切り
s = "abc def ghi"
split(s)
3-element Vector{SubString{String}}:
 "abc"
 "def"
 "ghi"
マルチバイト文字列が区切り
s = "あいう えおか きくけ"
split(s)
3-element Vector{SubString{String}}:
 "あいう"
 "えおか"
 "きくけ"
先頭に空白文字が付いた場合
s = "  abc def ghi"   # 全角空白(U+3000)+半角空白(U+0020)
split(s)
3-element Vector{SubString{String}}:
 "abc"
 "def"
 "ghi"

 先頭の空白文字が区切りとして処理されます。前述のとおり全角空白(U+3000)もUnicode カテゴリ Zs に含まれるので、区切りと認識されます。

困ったことというか、注意点というか、問題点というか

 例えば、単語ベクトルをテキストで表現する場合は、表記文字列+空白区切り+数値列(空白区切り)として記述します。

の 2.4798 -2.337 -2.44 -12.14 -0.83719 .....

 問題となるのは、先頭に記述される表記文字列に半角(U+0020)でない空白文字が出てくる場合があるということです。

  2.6146 -2.4845 -2.6105 -12.882 -1.0029 .....

 この場合に、split() を区切り文字なしで使ってしまうと、先頭の(本来切り出されるはずの)文字列が区切りとして扱われて消えてしまいます。
 マルチ文字を使わない言語では、この問題は発生しないので、そもそもプログラムを作成する際に考慮されていないことがあります。
 対策としては、日本語であれば split() の区切り文字として半角空白文字(U-0020)を指定すればいいのですが、他の言語圏で影響が出ないかどうかは確かめようがありません。つまるところ、マルチ文字を使わない言語圏で作られたプログラムで未考慮なのも、やむを得ないということでしょう。

 本質的には、これらを考慮したプログラムを書くべきであるのは言うまでもありませんが、上記のような事態を手っ取りばやく回避するにはどうすればいいのかと考えたところ、そもそものデータにUnicode カテゴリ Zs に含まれる文字を使わないように注意するほかないのではないでしょうか。

コメント

タイトルとURLをコピーしました