2017-05-31 7 views
-2

Ich muss eine kommagetrennte Zeichenfolge trennen, deren Inhalt manchmal zwischen Anführungszeichen steht. Ein Beispiel könnte sein:Getrennte Zeichenfolge trennen und Escape-Sequenzen entfernen

1, "TEST", 22345 "18,95", Ab "cde

Das erste Problem hier ist die Zeichenfolge aufteilen nur, wenn das Komma nicht umgeben ist durch Zitate wie "18,95". Ich habe das mit einem einfachen Regex gemacht. Das nächste Problem ist, die Zitate auszuschneiden, wo sie den Inhalt umgeben. Für "TEST" und "18,95" sollten die Zitate entfernt werden .Das Zitat in Ab cde sollte unberührt bleiben. Hier ist mein Code so weit:

List<string> results = Regex.Matches(this.Content, @"[\""](.+?)[\""]|[^,]+") 
          .Cast<Match>() 
          .Select(m => m.Value) 
          .Select(s => s.StartsWith("\"") && s.EndsWith("\"") ? s.Remove(1,1).Remove(s.Length-1,1) : s) 
          .ToList(); 

Für die zweite Select erhalte ich eine ArgumentOutOfRangeException seit dem zweiten Remove nicht mit s mehr funktioniert. Ich dachte, es sollte funktionieren, aber irgendwie nicht.

Wenn es einen besseren Weg dazu gibt, würde ich mich freuen, darüber zu erfahren.

+0

Haben Sie versuchen, eine CSV-Parser? –

+0

Hinweis: String ist unveränderlich. – Karolis

+0

@ WiktorStribiżew Ich versuche eine zu implementieren –

Antwort

2

Sie können den Wert in Anführungszeichen und den nicht notierten Wert in dem Namen Capture-Gruppen mit dem gleichen Namen erfassen und die angepassten Capture mit Match.Groups["group_name"] abrufen:

List<string> results = Regex.Matches(this.Content, @"[\""](?<value>.+?)[\""]|(?<value>[^,]+)") 
    .Cast<Match>() 
    .Select(m => m.Groups["value"].Value) 
    .ToList(); 

Demo: https://dotnetfiddle.net/M8lJDR

zu tragen Kontopotential leere Werte ändern + zu * und umgeben die Regex mit (?<=^|,) und (?=,|$):

List<string> results = Regex.Matches(input, 
     @"(?<=^|,)(?:""(?<value>.*?)""|(?<value>[^,]*))(?=,|$)") 
    .Cast<Match>() 
    .Select(m => m.Groups["value"].Value) 
    .ToList(); 

Demo: https://dotnetfiddle.net/WqRD20

+0

Wow. das ist ein guter! Perfekt. Haben Sie vielleicht auch eine Idee, wie ich die Regex anpassen könnte, um auch leere "Werte" zu erfassen. Wie in 1,2,, 4 würde es eine leere dritte Stelle geben, die zu einer leeren Zeichenfolge führen sollte. –

+0

Ändern Sie einfach die Quantifizierer von '+' in '*'. Sehen Sie die aktualisierte Demo –

+0

Ich dachte auch daran, aber leider fügt es ein leeres Ergebnis nach jedem "normalen" Ergebnis, das ich bereinigen müsste –

0

Nach dem Aufruf s.Remove(1,1) ist die resultierende Zeichenfolge kürzer als s (die unverändert bleibt)!

Verwenden

s.Remove(1,1).Remove(s.Length-2,1) 

oder

s.Remove(s.Length-1,1).Remove(1,1) 

anstelle von

s.Remove(1,1).Remove(s.Length-1,1) 

Th wird immer noch fehlschlagen, wenn s="\"". Um dies zu decken, müssen Sie den Zustand aktualisiert:

s.StartsWith("\"") && s.EndsWith("\"") && s.Length > 1 ? s.Remove(s.Length-1,1).Remove(1,1) : s 
+0

Das habe ich schon ausprobiert. funktioniert auch nicht –

0

Wie wäre es mit .Substring():

List<string> results = Regex.Matches(content, @"[\""](.+?)[\""]|[^,]+") 
         .Cast<Match>() 
         .Select(m => m.Value) 
         .Select(s => s.StartsWith("\"") && s.EndsWith("\"") 
          ? s.Substring(1, s.Length - 2) : s) 
         .ToList(); 

Ausgang:

1 
TEST 
22345 
18,95 
Ab"cde 

Hinweis: nicht richtig funktioniert für Teile die mehr als 2 Zitate enthalten.e ""test""work"",1

+0

Aber das ist genau, was ich nicht will, da die Zitate noch im Ergebnis sind –

+0

@ RomanoZumbé Vermutung, dass ich das verpasst habe. Die Antwort wurde aktualisiert, um stattdessen '.Substring()' zu verwenden. – degant

0

Vielleicht könnten Sie Schleife durch jede results und:

for (int i=0; i < results.Count; i++) 
{ 
    if (results[i].StartsWith("\"")) 
     results[i] = results[i].Remove(0, 1); 

    if (results[i].EndsWith("\"")) 
     results[i] = results[i].Remove(results[i].Length - 1, 1); 
} 
Verwandte Themen