C#の拡張方法文字列を分割するものを受け入れエスケープ文字
-
10-07-2019 - |
質問
書いていこうと思い延長方法。純Stringクラスです。思って補てんすることで、特別varationの分割方法をとるエスケープ文字の防止に分文字列の場合は、脱出の文字は使用の前にセパレーターが不要になる。
何を書く。私の非正規表現方法です。
といってもいい出来になっている署名様---
public static string[] Split(this string input, string separator, char escapeCharacter)
{
// ...
}
更新: で浮き彫りになった一つのコメントは、逃げ...
C#ソースコードを抜ける場合には非特殊文字のエラー CS1009:認識エスケープシーケンス.
IE JScriptのエスケープ文字は投げます。いない場合のみ\u、その"期待進数桁のエラーになります。いたしましFirefoxで動作と同じ.
私はこの方法は、僕の許のJavaScriptのモデルです。だか非区切りでまさに"お"を削除します。
解決
方法:
public static IEnumerable<string> Split(this string input,
string separator,
char escapeCharacter)
{
int startOfSegment = 0;
int index = 0;
while (index < input.Length)
{
index = input.IndexOf(separator, index);
if (index > 0 && input[index-1] == escapeCharacter)
{
index += separator.Length;
continue;
}
if (index == -1)
{
break;
}
yield return input.Substring(startOfSegment, index-startOfSegment);
index += separator.Length;
startOfSegment = index;
}
yield return input.Substring(startOfSegment);
}
それは動作するようです(いくつかの簡単なテスト文字列で)が、エスケープ文字は削除されません-それはあなたの正確な状況に依存します、私は疑います。
他のヒント
これは少しクリーンアップする必要がありますが、これは本質的にそれです...
List<string> output = new List<string>();
for(int i=0; i<input.length; ++i)
{
if (input[i] == separator && (i==0 || input[i-1] != escapeChar))
{
output.Add(input.substring(j, i-j);
j=i;
}
}
return output.ToArray();
最初の観察では、単一の文字を使用して文字列をエスケープするのは難しい場合があるため、区切り文字は文字列ではなく文字である必要があります-エスケープ文字は次の文字列をどれだけカバーしますか?それ以外は、@ James Curranの答えは、私がそれをどのように処理するかということです。たとえば、ループ初期化子でjを0に初期化します。 null入力などの処理方法を理解する
おそらくStringSplitOptionsもサポートし、コレクションに空の文字列を返すかどうかを指定する必要があります。
エスケープ文字を削除する場合の解決策です。
public static IEnumerable<string> Split(this string input,
string separator,
char escapeCharacter) {
string[] splitted = input.Split(new[] { separator });
StringBuilder sb = null;
foreach (string subString in splitted) {
if (subString.EndsWith(escapeCharacter.ToString())) {
if (sb == null)
sb = new StringBuilder();
sb.Append(subString, 0, subString.Length - 1);
} else {
if (sb == null)
yield return subString;
else {
sb.Append(subString);
yield return sb.ToString();
sb = null;
}
}
}
if (sb != null)
yield return sb.ToString();
}
このようなものを試すことができます。ただし、パフォーマンスが重要なタスクには安全でないコードで実装することをお勧めします。
public static class StringExtensions
{
public static string[] Split(this string text, char escapeChar, params char[] seperator)
{
return Split(text, escapeChar, seperator, int.MaxValue, StringSplitOptions.None);
}
public static string[] Split(this string text, char escapeChar, char[] seperator, int count)
{
return Split(text, escapeChar, seperator, count, StringSplitOptions.None);
}
public static string[] Split(this string text, char escapeChar, char[] seperator, StringSplitOptions options)
{
return Split(text, escapeChar, seperator, int.MaxValue, options);
}
public static string[] Split(this string text, char escapeChar, char[] seperator, int count, StringSplitOptions options)
{
if (text == null)
{
throw new ArgumentNullException("text");
}
if (text.Length == 0)
{
return new string[0];
}
var segments = new List<string>();
bool previousCharIsEscape = false;
var segment = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
if (previousCharIsEscape)
{
previousCharIsEscape = false;
if (seperator.Contains(text[i]))
{
// Drop the escape character when it escapes a seperator character.
segment.Append(text[i]);
continue;
}
// Retain the escape character when it escapes any other character.
segment.Append(escapeChar);
segment.Append(text[i]);
continue;
}
if (text[i] == escapeChar)
{
previousCharIsEscape = true;
continue;
}
if (seperator.Contains(text[i]))
{
if (options != StringSplitOptions.RemoveEmptyEntries || segment.Length != 0)
{
// Only add empty segments when options allow.
segments.Add(segment.ToString());
}
segment = new StringBuilder();
continue;
}
segment.Append(text[i]);
}
if (options != StringSplitOptions.RemoveEmptyEntries || segment.Length != 0)
{
// Only add empty segments when options allow.
segments.Add(segment.ToString());
}
return segments.ToArray();
}
}
public static string[] Split(this string input, string separator, char escapeCharacter)
{
Guid g = Guid.NewGuid();
input = input.Replace(escapeCharacter.ToString() + separator, g.ToString());
string[] result = input.Split(new string []{separator}, StringSplitOptions.None);
for (int i = 0; i < result.Length; i++)
{
result[i] = result[i].Replace(g.ToString(), escapeCharacter.ToString() + separator);
}
return result;
}
どのように変動するというのはそもそのる。基本的には、あらゆる場所の列の脱+seperatorが見つかったら、交換です(利用できるその他のランダムナメここでは関係ありません).その後の分割機能です。その置き換えることで、配列の各要素の脱出+seperator.
署名が正しくありません。文字列配列を返す必要があります警告は使用されていないため、いくつかのエラーはご容赦ください;)
public static List<String> Split(this string input, string separator, char escapeCharacter)
{
String word = "";
List<String> result = new List<string>();
for (int i = 0; i < input.Length; i++)
{
//can also use switch
if (input[i] == escapeCharacter)
{
break;
}
else if (input[i] == separator)
{
result.Add(word);
word = "";
}
else
{
word += input[i];
}
}
return result;
}
個人的にチートして、文字列を覗きます。リフレクターを使用して分割します... InternalSplitOmitEmptyEntries
は便利そうです;-)
この問題もありましたが、解決策が見つかりませんでした。だから私は自分でそのようなメソッドを書いた:
public static IEnumerable<string> Split(
this string text,
char separator,
char escapeCharacter)
{
var builder = new StringBuilder(text.Length);
bool escaped = false;
foreach (var ch in text)
{
if (separator == ch && !escaped)
{
yield return builder.ToString();
builder.Clear();
}
else
{
// separator is removed, escape characters are kept
builder.Append(ch);
}
// set escaped for next cycle,
// or reset unless escape character is escaped.
escaped = escapeCharacter == ch && !escaped;
}
yield return builder.ToString();
}
EscapeおよびUnescapeと組み合わせて、区切り文字とエスケープ文字をエスケープし、エスケープ文字を再度削除します。
public static string Escape(this string text, string controlChars, char escapeCharacter)
{
var builder = new StringBuilder(text.Length + 3);
foreach (var ch in text)
{
if (controlChars.Contains(ch))
{
builder.Append(escapeCharacter);
}
builder.Append(ch);
}
return builder.ToString();
}
public static string Unescape(string text, char escapeCharacter)
{
var builder = new StringBuilder(text.Length);
bool escaped = false;
foreach (var ch in text)
{
escaped = escapeCharacter == ch && !escaped;
if (!escaped)
{
builder.Append(ch);
}
}
return builder.ToString();
}
エスケープ/アンエスケープの例
separator = ','
escapeCharacter = '\\'
//controlCharacters is always separator + escapeCharacter
@"AB,CD\EF\," <=> @"AB\,CD\\EF\\\,"
分割:
@"AB,CD\,EF\\,GH\\\,IJ" => [@"AB", @"CD\,EF\\", @"GH\\\,IJ"]
使用するには、結合前にエスケープ、分割後にエスケープ解除します。
public string RemoveMultipleDelimiters(string sSingleLine)
{
string sMultipleDelimitersLine = "";
string sMultipleDelimitersLine1 = "";
int iDelimeterPosition = -1;
iDelimeterPosition = sSingleLine.IndexOf('>');
iDelimeterPosition = sSingleLine.IndexOf('>', iDelimeterPosition + 1);
if (iDelimeterPosition > -1)
{
sMultipleDelimitersLine = sSingleLine.Substring(0, iDelimeterPosition - 1);
sMultipleDelimitersLine1 = sSingleLine.Substring(sSingleLine.IndexOf('>', iDelimeterPosition) - 1);
sMultipleDelimitersLine1 = sMultipleDelimitersLine1.Replace('>', '*');
sSingleLine = sMultipleDelimitersLine + sMultipleDelimitersLine1;
}
return sSingleLine;
}