はじめに
文字列を分割する関数 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 文字
https://docs.julialang.org/en/v1/base/strings/#Base.Unicode.isspace'\t'
,'\n'
,'\v'
,'\f'
,'\r'
,' '
およびラテン 1 文字 U+0085、そして Unicode カテゴリ Zs に含まれる文字です。
Unicode カテゴリ Zs とは Space_Separator のことで、次の文字が含まれています。
Space(SP) | U+0020 |
No-Break Space(NBSP) | U+00A0 |
Ogham Space Mark | U+1680 |
En Quad | U+2000 |
Em Quad | U+2001 |
En Space | U+2002 |
Em Space | U+2003 |
Three-PerEm Space | U+2004 |
Four-Per-Em Space | U+2005 |
Six-Per-Em Space | U+2006 |
Figure Space | U+2007 |
Punctuation Space | U+2008 |
Thin Space | U+2009 |
Hair Space | U+200A |
Narrow No-Break Space(NNBSK) | U+202F |
Medium Mathematical Space(MMSP) | U+205F |
Ideographic Space | U+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 に含まれる文字を使わないように注意するほかないのではないでしょうか。
コメント