例えば:
c:\dir1 c:\dir2 "c:\my files" c:\code "old photos" "new photos"
リストとして読む必要があります:
- c:\ dir1
- c:\ dir2
- c:\myファイル
- c:\ code
- 古い写真
- 新しい写真
文字列を線形解析する関数を書くことはできますが、.NET 2.0ツールボックスに使用できるクールなトリックがあるかどうか疑問に思いましたか?
例えば:
c:\dir1 c:\dir2 "c:\my files" c:\code "old photos" "new photos"
リストとして読む必要があります:
文字列を線形解析する関数を書くことはできますが、.NET 2.0ツールボックスに使用できるクールなトリックがあるかどうか疑問に思いましたか?
すべてのキャラクターを攻撃しなければならないので、力ずくが最高のパフォーマンスを発揮すると思います。
そうすれば、すべての文字を正確に 1 回ヒットします。
また、実行される比較の数が制限されます。
static void Main(string[] args)
{
string input = @"c:\dir1 c:\dir2 ""c:\my files"" c:\code ""old photos"" ""new photos""";
List<string> splitInput = MySplit(input);
foreach (string s in splitInput)
{
System.Diagnostics.Debug.WriteLine(s);
}
System.Diagnostics.Debug.WriteLine(input);
}
public static List<string> MySplit(string input)
{
List<string> split = new List<string>();
StringBuilder sb = new StringBuilder();
bool splitOnQuote = false;
char quote = '"';
char space = ' ';
foreach (char c in input.ToCharArray())
{
if (splitOnQuote)
{
if (c == quote)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
splitOnQuote = false;
}
else { sb.Append(c); }
}
else
{
if (c == space)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
}
else if (c == quote)
{
if (sb.Length > 0)
{
split.Add(sb.ToString());
sb.Clear();
}
splitOnQuote = true;
}
else { sb.Append(c); }
}
}
if (sb.Length > 0) split.Add(sb.ToString());
return split;
}
通常、このタイプの問題では、フィールドを解析するための正規表現を開発できます。("(。*?)")は、すべての文字列値を引用符で囲みます。文字列からこれらの値をすべて削除し、引用符で囲まれたすべての項目がなくなった後、スペースで単純な分割を行うことができます。
static void Main(string[] args)
{
string myString = "\"test\" test1 \"test2 test3\" test4 test6 \"test5\"";
string myRegularExpression = @"""(.*?)""";
List<string> listOfMatches = new List<string>();
myString = Regex.Replace(myString, myRegularExpression, delegate(Match match)
{
string v = match.ToString();
listOfMatches.Add(v);
return "";
});
var array = myString.Split(' ');
foreach (string s in array)
{
if(s.Trim().Length > 0)
listOfMatches.Add(s);
}
foreach (string match in listOfMatches)
{
Console.WriteLine(match);
}
Console.Read();
}
残念ながら、これほど単純なC#カンフーはないと思います。明らかに、このアルゴリズムはアイテムを順不同で提供します...したがって、それが重要な場合...これは良い解決策ではありません。
これは、スペースで区切られたパスと引用符で囲まれたパスの両方をキャプチャする正規表現のみのソリューションです。引用符で囲まれたパスから引用符が削除され、複数のスペースによって空のリストエントリが作成されることはありません。スペースを挟まずに引用符で囲まれたパスと引用符で囲まれていないパスを混在させるエッジケースは、複数のエントリとして解釈されます。
未使用のグループのキャプチャを無効にすることで最適化できますが、代わりに読みやすさを向上させることを選択しました。
static Regex re = new Regex(@"^([ ]*((?<r>[^ ""]+)|[""](?<r>[^""]*)[""]))*[ ]*$");
public static IEnumerable<string> RegexSplit(string input)
{
var m = re.Match(input ?? "");
if(!m.Success)
throw new ArgumentException("Malformed input.");
return from Capture capture in m.Groups["r"].Captures select capture.Value;
}
(パスにスペースを含めることができるようにするため) 引用符で囲まれている場合を除いて、スペースが区切り記号として機能すると仮定すると、次のアルゴリズムをお勧めします。
ignore_space = false;
i = 0;
list_of_breaks=[];
while(i < input_length)
{
if(charat(i) is a space and ignore_space is false)
{
add i to list_of_breaks;
}
else if(charat(i) is a quote)
{
ignore_space = ! ignore_space
}
}
split the input at the indices listed in list_of_breaks