C#확장 방법-문자열을 분할 또한 수락이 탈출 캐릭터
-
10-07-2019 - |
문제
나는 다음과 같이 쓰는 확장을 위한 방법.NET String 클래스가 있습니다.나는 그것을 좋아하는 특별한 varation 에 분할 방법 중 하나는 이스케이프 문자 분할을 방지하기 위해 문자열을 때 escape 문자를 사용하기 전에 구분 기호입니다.
What's 를 작성하는 가장 좋은 방법은 이?저는 호기심에 대한 최고의 비 정규 표현식을 가까이하는 방법이다.
가명처럼...
public static string[] Split(this string input, string separator, char escapeCharacter)
{
// ...
}
업데이트: 기 때문에 그것은 와서 하나 의견을 탈출...
C#면을 탈출이 아닌 특별한 문자를 얻을 오류가-CS1009:인식할 수 없는 탈출 시퀀스입니다.
IE 에서 JScript escape 문자가 밖으로 던져.지 않는 한 당신이 시도하\u 그리고"예수의 자리"오류가 있습니다.테스트 파이어 폭스리고 그것은 동일한 동작이다.
나처럼 이 방법은 꽤 용서하고 따라 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);
}
그것은 몇 가지 빠른 테스트 문자열과 함께 작동하는 것처럼 보이지만 탈출 문자를 제거하지는 않습니다. 정확한 상황에 따라 다릅니다.
다른 팁
이것은 약간 청소해야하지만 이것은 본질적으로 IT입니다 ....
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으로 초기화합니다. 널 입력을 처리하는 방법을 알아 내기 등
아마도 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 발견,대 GUID(사용할 수 있는 다른 무작위는 쓰레기,여기에서는 중요하지 않습니다).다음 사용에 내장 분할 기능입니다.체에서 guid 를 각각 배열의 요소로 탈출+seperator.
서명이 올바르지 않으면 문자열 배열을 반환해야합니다.
Warnig는 확장을 사용한 적이 없으므로 몇 가지 오류에 대해 용서하십시오.)
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;
}
개인적으로 나는 속임수를 쓰고 string을 엿볼 수 있습니다. 반사기를 사용하여 스플릿 ... 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();
}
그것은 탈출과 외부와 함께 진행되며, 이는 분리기와 탈출 캐릭터를 빠져 나가고 탈출 캐릭터를 다시 제거합니다.
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;
}