文字列を区切り文字で分割したいのですが、結果には区切り文字を残しておきます。
C#でこれを行うにはどうすればよいですか?
区切り文字を「独自の分割」にする場合は、 Regex.Split を使用できます。例:
string input = "Plum-pear";
string pattern = "(-)";
string[] substrings = Regex.Split(input, pattern); // Split on hyphens
foreach (string match in substrings)
{
Console.WriteLine("'{0}'", match);
}
// The method writes the following to the console:
// 'Plum'
// '-'
// 'pear'
したがって、数式の分割を探している場合は、次の正規表現を使用できます
@"([*()\^\/]|(?<!E)[\+\-])"
これにより、1E-02のような定数も使用できるようになり、1E、-、および02に分割されるのを防ぐことができます。
そう:
Regex.Split("10E-02*x+sin(x)^2", @"([*()\^\/]|(?<!E)[\+\-])")
収量:
10E-02
*
x
+
sin
(
x
)
^
2
このバージョンはLINQまたはRegexを使用しないため、おそらく比較的効率的です。特別な区切り文字をエスケープすることを心配する必要がないので、正規表現よりも使いやすいと思います。常に配列に変換するよりも効率的なIList<string>
を返します。便利な拡張メソッドです。区切り文字は、配列または複数のパラメーターとして渡すことができます。
/// <summary>
/// Splits the given string into a list of substrings, while outputting the splitting
/// delimiters (each in its own string) as well. It's just like String.Split() except
/// the delimiters are preserved. No empty strings are output.</summary>
/// <param name="s">String to parse. Can be null or empty.</param>
/// <param name="delimiters">The delimiting characters. Can be an empty array.</param>
/// <returns></returns>
public static IList<string> SplitAndKeepDelimiters(this string s, params char[] delimiters)
{
var parts = new List<string>();
if (!string.IsNullOrEmpty(s))
{
int iFirst = 0;
do
{
int iLast = s.IndexOfAny(delimiters, iFirst);
if (iLast >= 0)
{
if (iLast > iFirst)
parts.Add(s.Substring(iFirst, iLast - iFirst)); //part before the delimiter
parts.Add(new string(s[iLast], 1));//the delimiter
iFirst = iLast + 1;
continue;
}
//No delimiters were found, but at least one character remains. Add the rest and stop.
parts.Add(s.Substring(iFirst, s.Length - iFirst));
break;
} while (iFirst < s.Length);
}
return parts;
}
いくつかのユニットテスト:
text = "[a link|http://www.google.com]";
result = text.SplitAndKeepDelimiters('[', '|', ']');
Assert.IsTrue(result.Count == 5);
Assert.AreEqual(result[0], "[");
Assert.AreEqual(result[1], "a link");
Assert.AreEqual(result[2], "|");
Assert.AreEqual(result[3], "http://www.google.com");
Assert.AreEqual(result[4], "]");
これを実現する最も簡単な方法は(Hans Kestingが提起した引数を除いて)、文字列を通常の方法で分割し、配列を反復処理して、最後を除くすべての要素に区切り文字を追加することです。
このような複数行の文字列を作成したかったのですが、改行を保持する必要があったため、これを実行しました
string x =
@"line 1 {0}
line 2 {1}
";
foreach(var line in string.Format(x, "one", "two")
.Split("\n")
.Select(x => x.Contains('\r') ? x + '\n' : x)
.AsEnumerable()
) {
Console.Write(line);
}
収量
line 1 one
line 2 two
同じ問題に遭遇しましたが、複数の区切り文字があります。これが私の解決策です:
public static string[] SplitLeft(this string @this, char[] delimiters, int count)
{
var splits = new List<string>();
int next = -1;
while (splits.Count + 1 < count && (next = @this.IndexOfAny(delimiters, next + 1)) >= 0)
{
splits.Add(@this.Substring(0, next));
@this = new string(@this.Skip(next).ToArray());
}
splits.Add(@this);
return splits.ToArray();
}
CamelCase変数名を分離したサンプル:
var variableSplit = variableName.SplitLeft(
Enumerable.Range('A', 26).Select(i => (char)i).ToArray());
私はこのコードを区切り文字を分割して保持するに書きました:
private static string[] SplitKeepDelimiters(string toSplit, char[] delimiters, StringSplitOptions splitOptions = StringSplitOptions.None)
{
var tokens = new List<string>();
int idx = 0;
for (int i = 0; i < toSplit.Length; ++i)
{
if (delimiters.Contains(toSplit[i]))
{
tokens.Add(toSplit.Substring(idx, i - idx)); // token found
tokens.Add(toSplit[i].ToString()); // delimiter
idx = i + 1; // start idx for the next token
}
}
// last token
tokens.Add(toSplit.Substring(idx));
if (splitOptions == StringSplitOptions.RemoveEmptyEntries)
{
tokens = tokens.Where(token => token.Length > 0).ToList();
}
return tokens.ToArray();
}
使用法例:
string toSplit = "AAA,BBB,CCC;DD;,EE,";
char[] delimiters = new char[] {',', ';'};
string[] tokens = SplitKeepDelimiters(toSplit, delimiters, StringSplitOptions.RemoveEmptyEntries);
foreach (var token in tokens)
{
Console.WriteLine(token);
}
veggerbyの回答はに変更されました
_var delimiter = "ab";
var text = "ab33ab9ab"
var parts = Regex.Split(text, $@"({Regex.Escape(delimiter)})")
.Where(p => p != string.Empty)
.ToList();
// parts = "ab", "33", "ab", "9", "ab"
_
Regex.Escape()
は、正規表現が特別なパターンコマンド(_*
_、_(
_など)として解釈する文字が区切り文字に含まれているため、エスケープする必要がある場合に備えてあります。
改行に文字が追加されないようにするには、次のようにしてください。
string[] substrings = Regex.Split(input,@"(?<=[-])");