RegexクラスのSplitメソッドを使用して、正規表現にマッチする部分をセパレーターとして、文字列を分割する方法を解説する。
正規表現パターンに一致する文字列をセパレーター(区切り)として使って文字列を分割するには、Regexクラス(System.Text.RegularExpressions名前空間)のSplitメソッドを利用する。本稿では、Splitメソッドの使い方を解説するとともに、少し高度な正規表現の書き方も紹介する。
RegexクラスのSplitメソッドは.NET Frameworkの初期からあるものだが、掲載したサンプルコードの全てを試すにはVisual Studio 2015以降が必要である。
なお、正規表現の書き方については、以下の.NET TIPSをご覧いただきたい。
RegexクラスのSplit静的メソッドを使えばよい(次のコード)。
なお、RegexクラスにはSplitインスタンスメソッドもある。また、Splitメソッドにオプション引数を渡す方法は、IsMatchメソッドなどと同じである。静的メソッドとインスタンスメソッドの使い分けや、オプション引数を渡す方法については、「.NET TIPS:正規表現を使って文字列がパターンに一致するか調べるには?[C#/VB]」をご覧いただきたい。
using System.Text.RegularExpressions;
……省略……
string[] result
= Regex.Split("{分割対象文字列}", "{正規表現パターン}");
Imports System.Text.RegularExpressions
……省略……
Dim result As String() _
= Regex.Split("{分割対象文字列}", "{正規表現パターン}")
上に示した書式だけを見ると、Stringクラス(System名前空間)のSplitメソッドと同じように思える。だが、セパレーターの指定に正規表現パターンが使えることで、柔軟で多彩な分割処理が可能になっているのだ。後述するように、CSVデータを項目に分解する処理なども行える。
まずは、正規表現パターンを使わないコンソールアプリの例を示そう(次のコード)。この場合は、StringクラスのSplitメソッドと同様の結果が得られる。コンソールに出力するための「DisplayAll」拡張メソッドをわざわざ作っているのは、以降のサンプルコードでも利用するためである。
using System.Text.RegularExpressions;
using static System.Console;
public static class StringArrayExtension
{
// 配列中の文字列を「'」で囲み、先頭に番号を付けて表示する
public static void DisplayAll(
this System.Collections.Generic.IEnumerable<string> words)
{
int count = 0;
foreach (var s in words)
WriteLine($"{++count}:'{s}'");
}
}
class Program
{
static void Main(string[] args)
{
// StringクラスのSplitメソッド
"吾輩は猫である。吾輩は子犬である。".Split('。')
.DisplayAll();
// 出力
// 1:'吾輩は猫である'
// 2:'吾輩は子犬である'
// 3:''
// RegexクラスのSplit静的メソッド
Regex.Split("吾輩は猫である。吾輩は子犬である。", "。")
.DisplayAll();
// 出力
// 1:'吾輩は猫である'
// 2:'吾輩は子犬である'
// 3:''
#if DEBUG
ReadKey();
#endif
}
}
Imports System.Text.RegularExpressions
Imports System.Console
Module StringArrayExtension
' 配列中の文字列を「'」で囲み、先頭に番号を付けて表示する
<System.Runtime.CompilerServices.Extension()>
Public Sub DisplayAll(words As IEnumerable(Of String))
Dim count As Integer = 0
For Each s In words
count += 1
WriteLine($"{count}:'{s}'")
Next
End Sub
End Module
Module Module1
Sub Main()
' StringクラスのSplitメソッド
Dim s = "吾輩は猫である。吾輩は子犬である。"
s.Split("。"c).DisplayAll()
' 1:'吾輩は猫である'
' 2:'吾輩は子犬である'
' 3:''
' RegexクラスのSplit静的メソッド
Regex.Split("吾輩は猫である。吾輩は子犬である。", "。") _
.DisplayAll()
' 1:'吾輩は猫である'
' 2:'吾輩は子犬である'
' 3:''
#If DEBUG Then
ReadKey()
#End If
End Sub
End Module
上のコードでは冒頭で2つの名前空間をインポートしている。同じインポートが以降のサンプルコードでも必要であるが、以降では省略させていただく。
RegexクラスのSplitメソッドでは、正規表現にマッチする文字列がセパレーターになるので、連続した2文字以上の文字列をセパレーターとして使うこともできる。
例えば、連続して2文字以上続く英数字をセパレーターとして使うには次のコードのようにする(1文字の英数字はセパレーターにしない)。
Regex.Split("吾輩は1匹の猫であるAbc吾輩は1匹の子犬である987",
"[A-Z0-9][A-Z0-9]+", RegexOptions.IgnoreCase)
.DisplayAll();
// 出力
// 1:'吾輩は1匹の猫である'
// 2:'吾輩は1匹の子犬である'
// 3:''
Regex.Split("吾輩は1匹の猫であるAbc吾輩は1匹の子犬である987",
"[A-Z0-9][A-Z0-9]+", RegexOptions.IgnoreCase) _
.DisplayAll()
' 出力
' 1:'吾輩は1匹の猫である'
' 2:'吾輩は1匹の子犬である'
' 3:''
セパレーターの一部または全部を結果に含めることもできる。それには、正規表現の中で、結果として取り出したい部分をかっこで囲ってグループにする。
例えば、上の例で「Abc」と「987」がセパレーターになった。その先頭の文字「A」と「9」も分割結果に含めるには、次のコードのようにする。
Regex.Split("吾輩は1匹の猫であるAbc吾輩は1匹の子犬である987",
"([A-Z0-9])[A-Z0-9]+", RegexOptions.IgnoreCase)
.DisplayAll();
// 出力
// 1:'吾輩は1匹の猫である'
// 2:'A'
// 3:'吾輩は1匹の子犬である'
// 4:'9'
// 5:''
Regex.Split("吾輩は1匹の猫であるAbc吾輩は1匹の子犬である987",
"([A-Z0-9])[A-Z0-9]+", RegexOptions.IgnoreCase) _
.DisplayAll()
' 出力
' 1:'吾輩は1匹の猫である'
' 2:'A'
' 3:'吾輩は1匹の子犬である'
' 4:'9'
' 5:''
キャプチャーされたグループが結果に含まれるのは、意図と異なることもある。例えば、セパレーターとして「である。」と「であるが、」の2つを指定しようとして次のようなコードを書くと、OR条件の範囲を限定するために付けたかっこもグループとしてキャプチャーされてしまう。
Regex.Split("吾輩は猫である。吾輩は子犬であるが、猫ではない。",
"である(。|が、)")
.DisplayAll();
// 出力
// 1:'吾輩は猫'
// 2:'。'
// 3:'吾輩は子犬'
// 4:'が、'
// 5:'猫ではない。'
Regex.Split("吾輩は猫である。吾輩は子犬であるが、猫ではない。",
"である(。|が、)") _
.DisplayAll()
' 出力
' 1:'吾輩は猫'
' 2:'。'
' 3:'吾輩は子犬'
' 4:'が、'
' 5:'猫ではない。'
非キャプチャーグループ化構成体「?:」は、かっこの中をキャプチャーさせないようにする(次のコード)。
Regex.Split("吾輩は猫である。吾輩は子犬であるが、猫ではない。",
"である(?:。|が、)")
.DisplayAll();
// 出力
// 1:'吾輩は猫'
// 2:'吾輩は子犬'
// 3:'猫ではない。'
Regex.Split("吾輩は猫である。吾輩は子犬であるが、猫ではない。",
"である(?:。|が、)") _
.DisplayAll()
' 出力
' 1:'吾輩は猫'
' 2:'吾輩は子犬'
' 3:'猫ではない。'
最後に、CSVのデータを分割する例を紹介しよう(次のコード)。
この正規表現の解読は、読者の皆さんへの宿題としたい。なお、これだけでは完璧とはいえないので注意してほしい。例えば、項目を囲む引用符「"」と項目中のエスケープされた引用符「""」はそのまま出力される(後処理として、項目の先頭と末尾から「"」を削る処理と、項目中の「""」を「"」に置換する処理が必要である)。
var csv = "猫, \"子犬\", , \"123,000\", 途中に\"\"引用符 , "
+ "途中に\r\n改行";
Regex.Split(csv, "\\s*,\\s*(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)").DisplayAll();
// 出力
// 1:'猫'
// 2:'"子犬"'
// 3:''
// 4:'"123,000"'
// 5:'途中に""引用符'
// 6:'途中に
// 改行'
Dim csv = "猫, ""子犬"", , ""123,000"", 途中に""""引用符 , " _
+ "途中に" + vbCrLf + "改行"
Regex.Split(csv, "\s*,\s*(?=(?:[^""]*""[^""]*"")*[^""]*$)").DisplayAll()
' 出力
' 1:'猫'
' 2:'"子犬"'
' 3:''
' 4:'"123,000"'
' 5:'途中に""引用符'
' 6:'途中に
' 改行'
正規表現を使って文字列を分割するには、RegexクラスのSplit静的メソッドを使えばよい(同じ処理を繰り返し実行すると分かっているなら、IsMatchメソッドの場合と同様にコンパイルオプション付きでRegexクラスのインスタンスを作り、Splitインスタンスメソッドを使う)。
また、本稿では正規表現を使ってCSVデータを分割する例も紹介した。正規表現について詳しくはMSDNの「.NET Framework の正規表現」をご覧いただきたい。
利用可能バージョン:.NET Framework 1.1以降(サンプルコードにはそれ以降の構文も含む)
カテゴリ:クラス・ライブラリ 処理対象:文字列
使用ライブラリ:Regexクラス(System.Text.RegularExpressions名前空間)
関連TIPS:正規表現を使ってパターンに一致する全ての文字列を抽出するには?[C#/VB]
関連TIPS:正規表現を使って文字列がパターンに一致するか調べるには?[C#/VB]
関連TIPS:正規表現を使って文字列を置換するには?[C#/VB]
関連TIPS:構文:クラス名を書かずに静的メソッドを呼び出すには?[C# 6.0]
関連TIPS:VB.NETでクラス名を省略してメソッドや定数を利用するには?
関連TIPS:Visual Studioでコンソール・アプリケーションのデバッグ実行時にコマンド・プロンプトを閉じないようにするには?
関連TIPS:正規表現を使って部分文字列を取得するには?[C#、VB]
関連TIPS:正規表現のパターン内にコメント文を記述するには?[C#、VB]
関連TIPS:CSVファイルを読み込むには?[2.0のみ、C#、VB]
関連TIPS:VB.NET固有の関数をC#で使用するには?
関連TIPS:文字列を文字列により分割するには?(VB.NET関数活用)
関連TIPS:Stringクラスにより文字列を文字列で分割するには?[2.0のみ、C#、VB]
Copyright© Digital Advantage Corp. All Rights Reserved.