普通、文字列を foreach で回すだけで文字列挙は可能だが、4Byte 文字が混じっていると話が違ってくる。
4Byte 文字はその名のとおり 4Byte なので char 型 2 個分に相当する。
※char 型 は 2Byte、.NET の内部文字コードは UTF-16
[文字列挙サンプル]
列挙に関しては、StringInfo.GetTextElementEnumerator があるが、TextElementEnumerator を返すため、少々使い勝手が悪い。
そこで、次の構造体(とおまけの拡張メソッド)を作成。
[使用例]
4Byte 文字はその名のとおり 4Byte なので char 型 2 個分に相当する。
※char 型 は 2Byte、.NET の内部文字コードは UTF-16
[文字列挙サンプル]
static void Main()
{
var text = "鮭𩸽"; // さけ(2Byte) ほっけ(4Byte)
Console.WriteLine(text.Length);
foreach( var c in text ) Console.WriteLine(c);
}
[結果]
3 鮭 � �※UTF-8 コードページによる表示なので、実行環境は PowerShell ISE 推奨
StringInfo
では、4Byte 文字も 1 文字として扱いたい場合なのだが、StringInfo が用意されている。列挙に関しては、StringInfo.GetTextElementEnumerator があるが、TextElementEnumerator を返すため、少々使い勝手が悪い。
そこで、次の構造体(とおまけの拡張メソッド)を作成。
public struct TextElementEnumerable : IEnumerable
{
public string Source;
public TextElementEnumerator GetEnumerator()
{
return StringInfo.GetTextElementEnumerator(Source);
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public static TextElementEnumerable Create(string source)
{
return new TextElementEnumerable() { Source = source };
}
}
// TextElementEnumerator が IEnumerator しか実装していないため、
// IEnumerable<string> が欲しい場合はキャストが必要
// ということを考慮した拡張メソッド
public static class TextExtensions
{
public static IEnumerable<string> GetTextElementEnumerable(this string source)
{
if( source == null ) throw new ArgumentNullException("source");
return TextElementEnumerable.Create(source).Cast<string>();
}
}
[使用例]
static void Main()
{
var text = "鮭𩸽"; // さけ(2Byte) ほっけ(4Byte)
// 4Byte 文字を考慮した文字数
Console.WriteLine(new StringInfo(text).LengthInTextElements);
// 4Byte 文字を考慮した文字列挙
foreach( var c in text.GetTextElementEnumerable() ) Console.WriteLine(c);
}
[結果]
2 鮭 𩸽
0 件のコメント:
コメントを投稿