2012-03-07 14 views
6

Potrzebuję zastąpić niektóre części ciągu za pomocą C#. Mogłem znaleźć tylko jedno podobne pytanie o tym, jak osiągnąć to here, ale to było PHP.Jak zamienić dwa lub więcej ciągów ze sobą?

Moja sytuacja wymaga słownik [ciąg, ciąg], który posiada par wymienić takie jak:

  • psa, kota
  • kot, mysz,
  • myszy, raptor

I Mam ciąg znaków o wartości:

"My dog ate a cat which once ate a mouse got eaten by a raptor" 

muszę funkcję, aby uzyskać w ten sposób:

"My cat ate a mouse which once ate a raptor got eaten by a raptor" 

Gdybym wyliczyć słownika i wywołać string.replace postanowieniem, otrzymuję to:

"My raptor ate a raptor which once ate a raptor got eaten by a raptor" 

To dziwne, jeśli ta nie została wezwana przed (Czy to powszechna wiedza?), Ale nie mogłem znaleźć żadnego. Więc przepraszam, jeśli tak było i tęskniłem za tym.

+0

Brudnym sposobem na to byłoby użycie tekstu pośredniego. Więc zamień "psa" na "1", "kota" na "2", a następnie wykonaj drugie przejście, w którym konwertujesz "1" i "2" na to, co chcesz. Upewnij się, że używasz czegoś bardziej unikalnego niż "1" i "2" (być może GUID). Tak jak powiedziałem, to jest brudne i jestem pewien, że jest lepszy sposób. – xbonez

+0

Co chcesz (jako wynik) dla słownika {"foo": "1", "bar": "2", "foobar": "3"}, i wpisać "foo bar foobarbar"? – Dogbert

+0

@Dogbert "1 2 32" –

Odpowiedz

9

Potrzebny jest proces dopasowywania do tylko raz. Po raz pierwszy myślę, że właściwą odpowiedzią jest w rzeczywistości "użyj regex"! Oto kod:

var replacements = new Dictionary<string, string> 
         { 
          { "do|g", "cat" }, 
          { "ca^t", "mouse" }, 
          { "mo$$use", "raptor" } 
         }; 

var source = "My do|g ate a ca^t which once ate a mo$$use"; 

var regexPattern = 
    "(" + 
    string.Join("|", replacements.Keys.Select(Regex.Escape)) + 
    ")"; 

var regex = new Regex(regexPattern); 

var result = regex.Replace(source, match => replacements[match.Value]); 

// Now result == "My cat ate a mouse which once ate a raptor" 

Wzór, który tutaj budujemy wygląda na (dog|cat|mouse). Każdy element w tym alternatywnym konstrukcie jest przepuszczany przez Regex.Escape, tak że znaczące dla wyrażenia regularnego znaki w kluczach (takie jak |, ^, itp.) Nie powodują problemów. Po znalezieniu pasującego tekstu zostanie on zastąpiony odpowiednią wartością w słowniku. Ciąg jest skanowany tylko raz, więc nie ma powtarzających się dopasowań, podobnie jak problem z iterowanym string.Replace.

+0

Lepsze i bardziej eleganckie niż moje rozwiązania. +1 ode mnie. –

+1

Dzięki za odpowiedź. To naprawdę jest eleganckie, ale ponieważ nie mam doświadczenia z regex; Muszę zapytać: co, gdybym próbował zastąpić psa ca | t? Czy istnieje sposób na zneutralizowanie części, które chcę zastąpić (jak ukośniki odwrotne i znak "|") i unikanie budowania czegoś takiego jak '(pies | ca | t | mysz)'? –

+0

@ d4wn doskonała uwaga. W razie potrzeby edytowałem użycie 'Regex.Escape'. – AakashM

1

To, czego potrzebujesz, to jednoczesne wykonywanie wszystkich zastępowanych napisów, abyś nie otrzymał kilku zamienników za ten sam token, prawda?

mogę myśleć o dwóch podejść, ani szczególnie eleganckie:

  • iteracyjnego słownika w określonej kolejności, więc można zawsze zastąpić mysz/raptor zanim kot/mysz.
  • Zamiast zamieniać kota na "mysz", zamień go na "$ mouse $" lub podobny znacznik. Zapewni to, że "$ mouse $" nie zostanie zastąpione przez "raptor" (lub, faktycznie, "$ raptor $"). Następnie, po zakończeniu przełączania, możesz usunąć wszystkie znaki "$".
+0

W punkcie pierwszym należy zastąpić w odwrotnej kolejności pytania, mysz -> raptor, następnie kot -> mysz, a następnie pies -> kot. – TheLukeMcCarthy

+0

W tej konkretnej próbie tak. Aby uzyskać bardziej ogólne rozwiązanie, musisz zbudować jakiś ukierunkowany acykliczny wykres, aby się upewnić. –

+0

To prawda, chciałem tylko podać konkretny przykład, aby d4wn mógł zobaczyć, dlaczego wcześniej nie działało. – TheLukeMcCarthy

Powiązane problemy