ワテの場合、C#を使って文字列を分割する処理を良く行う。
何らかの入力欄に入力された文字列を分割して、
[ いぬ 猫 たぬき ]
を
"いぬ" "猫" "たぬき"
こんなふうに三つの単語として取り出すなどだ。
さて、その文字列Split処理で今日一つ発見したので自分用の備忘録としてここにメモしておく。
セパレーターの文字をどのように指定して分割するのか?
想定される単語の区切り文字には、以下のものがあると思う。
‘ ‘ | 半角空白 |
‘ ’ | 全角空白 |
\t | タブ |
などだ。
場合によっては ‘\r’ や ‘\n’ などの改行コードでも区切りたい場合もある。
さて、昔のワテの場合には、
var words = " いぬ 猫 たぬき ".Split(new char[] { ' ', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
のように区切り文字をずらずらと並べていた。
並べるのが面倒な場合には、ToCharArray() を用いる小細工で、
var words = " いぬ 猫 たぬき ".Split(" \t\r\n".ToCharArray() , StringSplitOptions.RemoveEmptyEntries);
こんなふうにしても良い。
今日、もっと良い方法を発見した。
C#で文字列を単語に分割するお勧めの方法
それがこれだ。
var wordsArr2 = words.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); var wordsArr3 = words.Split(null).Where(s => s != string.Empty).ToArray();
つまり、Split の引数に null か new char[0] を与えると空白文字で分割してくれるのだ。
テスト用のC#の全ソースコードを以下に示す。
実行すると、コンソールウインドウが表示されて、結果が見られる。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _2016_09_17_CSharpStringSplit { class Program { static void Main(string[] args) { var words = " 単語1 単語2 単語3 単語4\r\n単語5\r単語6 "; // T T ~T~~ ~~~T~~~~ ~~T~~ T T // 半角 半角 全角 タブ CRLF CR 半角 var wordsArr1 = words.Split(new char[] { ' ', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); var wordsArr2 = words.Split(new char[0], StringSplitOptions.RemoveEmptyEntries); var wordsArr3 = words.Split(null).Where(s => s != string.Empty).ToArray(); Console.WriteLine("-従来式--------------------------------"); for (int i = 0; i < wordsArr1.Length; i++) { Console.WriteLine("wordsArr1[{0}] = ->{1}<-", i, wordsArr1[i]); } Console.WriteLine("-新方式1-------------------------------"); for (int i = 0; i < wordsArr2.Length; i++) { Console.WriteLine("wordsArr2[{0}] = ->{1}<-", i, wordsArr2[i]); } Console.WriteLine("-新方式2-------------------------------"); for (int i = 0; i < wordsArr3.Length; i++) { Console.WriteLine("wordsArr3[{0}] = ->{1}<-", i, wordsArr3[i]); } } } }
その実行結果
-従来式-------------------------------- wordsArr1[0] = ->単語1<- wordsArr1[1] = ->単語2<- wordsArr1[2] = ->単語3<- wordsArr1[3] = ->単語4 単語6<- -新方式1------------------------------- wordsArr2[0] = ->単語1<- wordsArr2[1] = ->単語2<- wordsArr2[2] = ->単語3<- wordsArr2[3] = ->単語4<- wordsArr2[4] = ->単語5<- wordsArr2[5] = ->単語6<- -新方式2------------------------------- wordsArr3[0] = ->単語1<- wordsArr3[1] = ->単語2<- wordsArr3[2] = ->単語3<- wordsArr3[3] = ->単語4<- wordsArr3[4] = ->単語5<- wordsArr3[5] = ->単語6<- 続行するには何かキーを押してください . . .
二通りの新方式は、共に同じ結果になっている。
なお、従来式で “単語5” が表示されないのは何でかな?
分からん。
まあ、いいか。
以下、新方式の解説。
なお、新方式と言っても従来からある手法なので、あくまでワテにとっての新方式と言う意味である。
String.Split Method (Char[])
MSDNのこのページによると、
The separator array
Each element of separator defines a separate delimiter that consists of a single character.If the separator argument is null or contains no characters, the method treats white-space characters as the delimiters.
White-space characters are defined by the Unicode standard; they return true if they are passed to the Char.IsWhiteSpace method.
要約するとSplitの第一引数である seperator 配列が null か 一つも文字が無い場合には、空白文字で分割する。
空白文字とは、Char.IsWhiteSpace() メソッドがtrueを返す文字。
と言う事である。
つまり、以下に引用する文字が空白文字だ。
空白文字は、次の Unicode 文字です。
メンバー、UnicodeCategory.SpaceSeparatorカテゴリで、スペース文字が含まれています (u+0020) 非分割領域 (U + 00A0)、OGHAM 領域のマーク (U + 1680)、EN クアッド (U + 2000)、EM クアッド (U + 2001 年)、半角スペース (U + 2002)、EM 容量 (U + 2003)、3-EM ごとの領域 (U + 2004 年)、4-EM ごとの領域 (U+ 2005)、6-EM ごとの領域 (U + 2006 年)、図の領域 (U + 2007)、句読点をシン (U + 2008 年)、スペース (U + 2009 年)、スペース髪の毛領域 (200 U + a)、幅の狭い非分割領域 (U + 202F)、MEDIUM 数学的な領域 (U + 205F)、および全角スペース (U + 3000)。
メンバー、UnicodeCategory.LineSeparatorカテゴリで、行区切り記号の文字だけで構成されます (u+2028)。
メンバー、UnicodeCategory.ParagraphSeparatorカテゴリで、段落区切り記号の文字だけで構成されます (u+2029)。
集計の文字の文字 (u+0009)、ライン フィード (u+000 a)、行の集計 (U + 000B)、フォーム (U + 000 C) のフィード、キャリッジ リターン (U+000D)、および次の行 (U + 0085)。
引用元 https://docs.microsoft.com/ja-jp/dotnet/api/system.char.iswhitespace?view=netframework-4.7.2
まあ、こんなのは覚えられないと思うので、良く使いそうな空白文字を太字で示しておいた。
なので、この新方式を使うと、半角空白、全角空白、タブはもちろん、’\r’ や ‘\n’ などでも分割してくれる。
逆に言えば、もし、特定の文字でのみ分割したい場合には、冒頭で紹介したように自前のchar[]配列を用意して、以下のようにSplitすれば良いだろう。
var words = " いぬ 猫 たぬき ".Split(new char[] { ' ', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var words = " いぬ 猫 たぬき ".Split(" \t\r\n".ToCharArray() , StringSplitOptions.RemoveEmptyEntries);
なお、新方式では null を指定した場合には、何故か第二引数を与える事が出来ない。
var wordsArr3 = words.Split(null, StringSplitOptions.RemoveEmptyEntries); // これはエラーした
従って、nullで分割したSplit結果配列の中から空文字列を除去した場合には、上記のコードのように、LINQを使って空要素を除去するなどの小細工が必要だ。
var wordsArr3 = words.Split(null).Where(s => s != string.Empty).ToArray();
でもそんな事をするくらいなら、new char[0] を使う方式が最も手っ取り早いだろう。
var wordsArr2 = words.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
と言う事でこの手法が最もお勧めかな。
まとめ
C#は奥が深い。
- C#で文字列を分割して単語配列を作成する場合には String.Split() メソッドがお勧め
- 分割のセパレーター文字を指定する場合には個々の文字をchar型配列で指定しても良い
- 分割のセパレーター文字を null か new char[0] にすると空白文字が分割に使われるので楽チン
- 空白文字とは Char.IsWhiteSpace()メソッドがtrueを返す文字
と言う事で、ワテの場合C#のString.Splitでは今後は
var wordsArr2 = words.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
この方式を使う予定だ。
C#の本を買う
アマゾンのレビューコメントでも結構高い評価が付いている。
マイクロソフト公式なら間違いないか?
定番の「独習C# 」だ。
こういう本をすらすらと読みこなせるくらいの知識を身に付ければあなたも上級者レベルになれるだろう。
コメント