2011-02-06 15 views
24

pracuję nad aplikacji, który importuje tysiące wierszy, gdzie każda linia ma format takiego:C# Regex.Split: Usuwanie pustych wyników

|* 9070183020 |04.02.2011 |107222  |M/S SUNNY MEDICOS     |GHAZIABAD       |  32,768.00 | 

Używam następujący Regex podzielić linie na dane potrzebne:

Regex lineSplitter = new Regex(@"(?:^\|\*|\|)\s*(.*?)\s+(?=\|)"); 
string[] columns = lineSplitter.Split(data); 

foreach (string c in columns) 
    Console.Write("[" + c + "] "); 

To daje mi następujący wynik:

[] [9070183020] [] [04.02.2011] [] [107222] [] [M/S SUNNY MEDICOS] [] [GHAZIABAD] [] [32,768.00] [|] 

N ow mam dwa pytania.
1. Jak usunąć puste wyniki. wiem, że mogę używać:

string[] columns = lineSplitter.Split(data).Where(s => !string.IsNullOrEmpty(s)).ToArray(); 

ale jest tam żadnych budowane w sposób usuwania pustych wyniki?

2. Jak mogę usunąć ostatnią rurę?

Dziękuję za pomoc.
Pozdrawiam,
Yogesh.

EDYCJA: Myślę, że moje pytanie było trochę źle zrozumiane. Nigdy nie było o jak mogę to zrobić. Było tylko około jak mogę to zrobić, zmieniając Regex w powyższym kodzie.

Wiem, że mogę to zrobić na wiele sposobów. I zrobiono go z kodem wspomniano powyżej, z Where klauzuli iz alternatywnym sposób, który jest również (więcej niż dwa razy) szybciej:

Regex regex = new Regex(@"(^\|\*\s*)|(\s*\|\s*)"); 
data = regex.Replace(data, "|"); 

string[] columns = data.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); 

Po drugie, w przypadku testowego, mój system może analizować 92K + takie linie w mniej niż 1,5 sekundy w oryginalnej metodzie iw mniej niż 700 milisekund w drugiej metodzie, gdzie nigdy nie znajdę więcej niż kilka tysięcy w rzeczywistych przypadkach, więc nie sądzę, że muszę myśleć o prędkości tutaj . Moim zdaniem myślenie o prędkości w tym przypadku to przedwczesna optymalizacja.

znalazłem odpowiedzi na moje pierwsze pytanie: nie można zrobić z Split jak nie ma takiej opcji wybudowany w

Nadal szukasz odpowiedzi na moje drugie pytanie..

+0

Odpowiadając na pierwsze pytanie, uważamy, że częścią wyrażenia regularnego powinno być '@" (. +?) "'. W przeciwnym razie możliwe byłoby dopasowanie pustych pól (co teraz masz). –

+0

W tym przypadku nie ma to większego znaczenia, Jeff. Da to dokładnie taki sam wynik. – Yogesh

+0

Tak jak w notatce, o której wspominasz tysiące wpisów: Używanie String.Split, a następnie robienie więcej Przetwarzanie ciągów jest znacznie szybsze niż używanie Regexa w pierwszej kolejności. – Foxfire

Odpowiedz

37
Regex lineSplitter = new Regex(@"[\s*\*]*\|[\s*\*]*"); 
var columns = lineSplitter.Split(data).Where(s => s != String.Empty); 

lub można po prostu zrobić:

string[] columns = data.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries); 
foreach (string c in columns) this.textBox1.Text += "[" + c.Trim(' ', '*') + "] " + "\r\n"; 

I nie, nie ma opcji, aby usunąć puste wpisy dla RegEx.Split jak dla String.split.

Możesz również użyć dopasowań.

+0

+1 za odpowiedź na moje pierwsze pytanie. To także znalazłem czytając w dokumentach net i msdn. – Yogesh

+0

Ponadto, jeśli spróbujesz mojego RegEx, zobaczysz, że nie ma pustych wartości z wyjątkiem na początku i na końcu tablicy. –

+0

Oznaczono jako wybraną jako najbliższą. Używam drugiego podejścia, o którym wspomniałem w swoim pytaniu, aby być szybszym. Dzięki. – Yogesh

0

Jak o tym:

zakładając mamy linię:

line1="|* 9070183020 |04.02.2011 |107222  |M/S SUNNY MEDICOS     |GHAZIABAD       |  32,768.00 |"; 

możemy mieć wymagany wynik:

string[] columns =Regex.Split(line1,"|"); 
foreach (string c in columns) 
     c=c.Replace("*","").Trim(); 

to daje następujący wynik:

[9070183020] [04.02.2011] [107222] [M/S SUNNY MEDICOS] [GHAZIABAD] [32,768.00] 
0

Mogę mieć wro ng pomysł tutaj, ale chcesz po prostu podzielić ciąg data używając '|' znak jako ogranicznik? W takim przypadku możesz:

string[] result = data.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).ToArray(); 

Spowoduje to zwrócenie wszystkich pól bez spacji i pustych pól usuniętych. Możesz to, co lubisz w części Select sformatować wyniki, np.

.Select(d => "[" + d.Trim() + "]").ToArray(); 
1

Jako alternatywę do podziału, który zawsze będzie powodować problemy, gdy ograniczniki są również obecne na początku i na końcu wejście, można spróbować dopasowanie zawartości wewnątrz rur:

foreach (var token in Regex.Matches(input, @"\|\*?\s*(\S[^|]*?)\s*(?=\|)")) 
{ 
    Console.WriteLine("[{0}]", token.Groups[1].Value); 
} 

// Prints the following: 
// [9070183020] 
// [04.02.2011] 
// [107222] 
// [M/S SUNNY MEDICOS] 
// [GHAZIABAD] 
// [32,768.00] 
0

Don w ogóle używaj wyrażenia regularnego w twoim przypadku. Nie wydaje się, abyś go potrzebował, a wyrażenia regularne są znacznie wolniejsze (i mają dużo wyższy narzut) niż bezpośrednio za pomocą funkcji łańcuchowych.

więc użyć trochę jak:

const Char[] splitChars = new Char[] {'|'}; 

string[] splitData = data.Split(splitChars, StringSplitOptions.RemoveEmptyEntries) 
2

myślę, że może to działać jako ekwiwalent usunięcie pustych strun:

string[] splitter = Regex.Split(textvalue,@"\s").Where(s => s != String.Empty).ToArray<string>(); 
+0

Dobry przykład na małe rzeczy, które Linq ma znacznie lepsze :) –

0

podstawie @Jaroslav wielką odpowiedź Jandek za napisałem extension method, ja połóż to tutaj, może to może zaoszczędzić twój czas.

/// <summary> 
/// String.Split with RemoveEmptyEntries option for clean up empty entries from result 
/// </summary> 
/// <param name="s">Value to parse</param> 
/// <param name="separator">The separator</param> 
/// <param name="index">Hint: pass -1 to get Last item</param> 
/// <param name="wholeResult">Get array of split value</param> 
/// <returns></returns> 
public static object CleanSplit(this string s, char separator, int index, bool wholeResult = false) 
{ 
    if (string.IsNullOrWhiteSpace(s)) return ""; 

    var split = s.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries); 

    if (wholeResult) return split; 

    if (index == -1) return split.Last(); 

    if (split[index] != null) return split[index]; 

    return ""; 
} 
0

1. Jak usunąć puste wyniki?

Można użyć LINQ aby usunąć wszystkie wpisy, które są równe string.Empty:

string[] columns = lineSplitter.Split(data); 
columns = columns.ToList().RemoveAll(c => c.Equals(string.Empty)).ToArray(); 

2. W jaki sposób mogę usunąć ostatni rurę?

Można użyć LINQ tutaj, aby usunąć wszystkie wpisy równe charakteru, które chcesz usunąć:

columns = columns.ToList().RemoveAll(c => c.Equals("|")).ToArray(); 
0

Zastosowanie tego rozwiązania:

string stringwithDelemeterNoEmptyValues= string.Join(",", stringwithDelemeterWithEmptyValues.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); 
Powiązane problemy