2010-07-01 19 views
6

Jaki jest najszybszy sposób analizowania ciągów w języku C#?Szybkie parsowanie ciągów w C#

Obecnie używam tylko indeksowania ciągów (string[index]) i kod działa rozsądnie, ale nie mogę pomóc, ale myślę, że ciągły zakres sprawdzania, czy indeksujący akcesor musi coś dodawać.

Zastanawiam się, jakie techniki powinienem rozważyć, aby to zwiększyć. To są moje wstępne przemyślenia/pytania:

  1. Stosować metody jak string.IndexOf() i IndexOfAny() znaleźć znaki zainteresowania. Czy są one szybsze niż ręczne skanowanie ciągu znaków przez string[index]?
  2. Użyj regex. Osobiście nie lubię wyrażenia regularnego, ponieważ uważam je za trudne do utrzymania, ale czy są one prawdopodobnie szybsze niż ręczne skanowanie ciągu znaków?
  3. Użyj niebezpiecznego kodu i wskaźników. To wyeliminowałoby sprawdzanie zakresu indeksu, ale czytałem, że ten niebezpieczny kod nie działa w niezaufanych środowiskach. Jakie są dokładnie tego konsekwencje? Czy to oznacza, że ​​cały zespół nie załaduje się/uruchomi, czy tylko kod oznaczony jako niebezpieczny odmówić uruchomienia? Biblioteka mogłaby potencjalnie być używana w wielu środowiskach, więc aby móc powrócić do wolniejszego, ale bardziej kompatybilnego byłoby miło.
  4. Co jeszcze mogę wziąć pod uwagę?

NB: Powinienem powiedzieć, że ciągi, które analizuję, mogą być dość duże (powiedzmy 30k) oraz w niestandardowym formacie, dla którego nie ma standardowego parsera .NET. Ponadto, wykonanie tego kodu nie jest zbyt krytyczne, więc jest to po części teoretyczna kwestia ciekawości.

+3

Bardzo trudno jest odpowiedzieć, jeśli nie podasz więcej szczegółów/kodu, aby wyjaśnić, co dokładnie i jak "parsuje". – Grzenio

+1

Nie chcę być dla ciebie niegrzeczny, ale to wygląda na przedwczesną optymalizację, znak ostrzegawczy programisty z wykształceniem C. Prawdopodobnie masz na to więcej pilnych problemów. – reinierpost

+0

@reinierpost: Czy tęskniłeś za tym, że PO powiedział "częściowo tylko teoretyczne pytanie o ciekawość"? – LukeH

Odpowiedz

2

30k nie jest tym, co uważam za duże. Zanim się ekscytuję, będę profilować. Wskaźnik powinien być w porządku, aby uzyskać najlepszą równowagę między elastycznością i bezpieczeństwem.

Na przykład, aby utworzyć ciąg 128k (i osobną tablicę o tym samym rozmiarze), wypełnij go śmieciami (w tym czasem do obsługi Random) i zsumuj wszystkie punkty kodowe znaków za pomocą indeksera ... 3ms:

 var watch = Stopwatch.StartNew(); 
     char[] chars = new char[128 * 1024]; 
     Random rand = new Random(); // fill with junk 
     for (int i = 0; i < chars.Length; i++) chars[i] = 
      (char) ((int) 'a' + rand.Next(26)); 

     int sum = 0; 
     string s = new string(chars); 
     int len = s.Length; 
     for(int i = 0 ; i < len ; i++) 
     { 
      sum += (int) chars[i]; 
     } 
     watch.Stop(); 
     Console.WriteLine(sum); 
     Console.WriteLine(watch.ElapsedMilliseconds + "ms"); 
     Console.ReadLine(); 

dla plików faktycznie duże, o czytelnik podejście powinno być stosowane - StreamReader itp

+0

Lub jeśli umieścisz Stopwatch.StartNew pod nowym ciągiem znaków (znaki) = 0 ms – simendsjo

+0

Dzięki Marc. Prawe 30k nie jest duże, ale miałem na myśli, że nie jest to ciąg jednoliniowy lub konwertowanie ciągu na liczbę całkowitą. Z pewnością wystarczająco mały, aby zmieścić się w pamięci. 3ms brzmi dobrze, ale myślę, że po prostu będę musiał profilować i porównywać. –

1

"Przetwarzanie" jest dość niedokładny termin. Ponieważ mówimy o 30k, wydaje się, że możesz mieć do czynienia z jakimś uporządkowanym łańcuchem, który można uwzględnić tworząc parser za pomocą narzędzia generatora parsera.

Miłym narzędziem do tworzenia, utrzymywania i zrozumieć cały proces jest system GOLD analizowaniem Devin Cooka: http://www.devincook.com/goldparser/

To może pomóc w tworzeniu kodu, który jest skuteczny i właściwy dla wielu potrzeb tekstowy analizowania.

Co do twoich punktów:

  1. zwykle nie jest przydatny do analizowania, która idzie dalej niż dzielenie ciąg.

  2. lepiej pasuje, jeśli nie ma rekurencji lub zbyt skomplikowanych reguł.

  3. jest po prostu nie-iść, jeśli tak naprawdę nie zidentyfikowano tego jako poważny problem. JIT może zająć się sprawdzaniem zasięgu tylko w razie potrzeby, a nawet w przypadku prostych pętli (typowa pętla for) jest to całkiem dobrze obsługiwane.

+0

Dzięki Lucero. Złoto wygląda całkiem nieźle, ale nie nadaje się do tego, co robię (bardzo białe i nieokreślone). –

+0

cantabilesoftware, bez większej wiedzy o tym, co faktycznie próbujesz zrobić, jest dość trudne do sformułowania znaczących sugestii. – Lucero