Muszę poszukać ciąg i zastąpić wszystkie wystąpienia %FirstName%
i %PolicyAmount%
o wartości pobierane z bazy danych. Problem polega na tym, że wielkość liter w FirstName jest różna. To uniemożliwia mi użycie tej String.Replace()
metody. Widziałem strony internetowe na ten temat, które sugerują
Regex.Replace(strInput, strToken, strReplaceWith, RegexOptions.IgnoreCase);
Jednak z jakiegoś powodu, gdy próbuję i zastąpić %PolicyAmount%
ze $0
nigdy wymiana odbywa. Zakładam, że ma to coś wspólnego ze znakiem dolara będącym zarezerwowaną postacią w wyrażeniu regularnym.
Czy mogę zastosować inną metodę, która nie wymaga dezynfekcji danych wejściowych w celu radzenia sobie ze znakami specjalnymi wyrażeń regularnych?
Odpowiedzi:
Od MSDN
0 USD - „Zastępuje ostatni podciąg zgodny z numerem grupy (dziesiętnym)”.
W .NET Wyrażenia regularne grupa 0 jest zawsze całym dopasowaniem. Aby uzyskać dosłowny $ musisz
źródło
Wydaje się, że
string.Replace
powinien mieć przeciążenie, które wymagaStringComparison
argumentu. Ponieważ tak nie jest, możesz spróbować czegoś takiego:źródło
ReplaceString
naReplace
.oldValue == newValue == ""
.ReplaceString("œ", "oe", "", StringComparison.InvariantCulture)
rzucaArgumentOutOfRangeException
.Rodzaj mylącej grupy odpowiedzi, po części dlatego, że tytuł pytania jest w rzeczywistości znacznie większy niż zadawane pytanie szczegółowe. Po przeczytaniu nie jestem pewien, czy odpowiedź jest kilka zmian od przyswojenia wszystkich dobrych rzeczy tutaj, więc pomyślałem, że spróbuję podsumować.
Oto metoda rozszerzenia, która moim zdaniem pozwala uniknąć wspomnianych tutaj pułapek i zapewnia najszerzej stosowane rozwiązanie.
Więc...
"œ".ReplaceCaseInsensitiveFind("oe", "")
choć może on mieć nieco inne zachowanie w umyśle.Niestety, komentarz @HA, który masz do
Escape
wszystkich trzech, jest niepoprawny . Wartość początkowa inewValue
nie musi być.Uwaga: Musisz jednak uciec
$
s w nowej wartości, którą wstawiasz, jeśli są częścią czegoś, co wydaje się być znacznikiem „przechwyconej wartości” . Zatem trzy znaki dolara w Regex.Replace wewnątrz Regex.Replace [sic]. Bez tego coś takiego się psuje ..."This is HIS fork, hIs spoon, hissssssss knife.".ReplaceCaseInsensitiveFind("his", @"he$0r")
Oto błąd:
Powiem ci co, wiem, że ludzie, którzy czują się komfortowo z Regex, czują, że ich użycie pozwala uniknąć błędów, ale często wciąż jestem stronniczy w bajtowaniu ciągów wąchania (ale dopiero po przeczytaniu Spolskyego na temat kodowania ), aby mieć absolutną pewność, że otrzymujesz to, co masz przeznaczony do ważnych zastosowań. Trochę przypomina mi Crockforda o „ niepewnych wyrażeniach regularnych ”. Zbyt często piszemy wyrażenia regularne, które pozwalają na to, czego chcemy (jeśli mamy szczęście), ale przypadkowo dopuszczają więcej (np. Czy
$10
naprawdę jest prawidłowym ciągiem „wartość przechwytywania” w moim nowym wyrażeniu regularnym powyżej?), Ponieważ nie byliśmy wystarczająco rozważni . Obie metody mają wartość i obie zachęcają do różnego rodzaju niezamierzonych błędów. Często łatwo jest nie docenić złożoności.Ta dziwna
$
ucieczka (i któraRegex.Escape
nie uciekła z przechwyconych wzorców wartości, tak$0
jak bym się spodziewał po wartościach zastępczych) doprowadziła mnie na chwilę do szaleństwa. Programowanie jest trudne (c) 1842źródło
Oto metoda rozszerzenia. Nie jestem pewien, gdzie to znalazłem.
źródło
Wydaje się, że najłatwiejszą metodą jest po prostu użycie metody Zamień, która jest dostarczana z .Net i jest dostępna od .Net 1.0:
Aby użyć tej metody, musisz dodać odwołanie do zestawu Microsoft.VisualBasic. Ten zestaw jest standardową częścią środowiska wykonawczego .Net, nie jest dodatkowym plikiem do pobrania ani oznaczony jako przestarzały.
źródło
C. Dragon 76
działała zgodnie z oczekiwaniami.źródło
Zainspirowany odpowiedzią cfeduke, stworzyłem tę funkcję, która używa IndexOf do znalezienia starej wartości w ciągu, a następnie zastępuje ją nową wartością. Użyłem tego w skrypcie SSIS przetwarzającym miliony wierszy, a metoda wyrażenia regularnego była znacznie wolniejsza niż ta.
źródło
Rozwijając popularną odpowiedź C. Dragon 76 , zmieniając jego kod w rozszerzenie, które przeciąża domyślną
Replace
metodę.źródło
Na podstawie odpowiedzi Jeffa Reddy'ego, z pewnymi optymalizacjami i walidacjami:
źródło
wersja podobna do C. Dragon's, ale jeśli potrzebujesz tylko jednego zamiennika:
źródło
Oto kolejna opcja wykonania zamiany Regex, ponieważ wydaje się, że niewiele osób zauważa, że dopasowania zawierają lokalizację w ciągu:
źródło
źródło
Metoda wyrażeń regularnych powinna działać. Jednak to, co możesz zrobić, to ciąg znaków z bazy danych małymi literami, małe zmienne%, które masz, a następnie zlokalizuj pozycje i długości w łańcuchu małych liter z bazy danych. Pamiętaj, że pozycje w ciągu nie zmieniają się tylko dlatego, że są małe.
Następnie za pomocą pętli, która idzie w odwrotnym kierunku (jest łatwiej, jeśli nie musisz, musisz mieć bieżącą liczbę miejsc, do których przenoszą się późniejsze punkty), usuń z bazy danych ciąg znaków innych niż małe litery z bazy danych zmienne% według ich pozycji i długość i wstaw wartości zastępcze.
źródło
(Ponieważ wszyscy to robią). Oto moja wersja (z zerowymi testami oraz poprawnym wprowadzaniem i zastępowaniem znaków zastępczych) ** Inspirowane z internetu i innych wersji:
Stosowanie:
źródło
Pozwól, że przedstawię moją sprawę, a jeśli chcesz, możesz mnie rozerwać na strzępy.
Regex nie jest odpowiedzią na ten problem - relatywnie zbyt wolny i głodny pamięci.
StringBuilder jest znacznie lepszy niż string-string.
Ponieważ będzie to metoda rozszerzenia w celu uzupełnienia
string.Replace
, uważam, że ważne jest dopasowanie sposobu, w jaki to działa - dlatego ważne jest zgłaszanie wyjątków dla tych samych problemów argumentów, podobnie jak zwracanie oryginalnego ciągu, jeśli nie dokonano zamiany.Uważam, że posiadanie parametru StringComparison nie jest dobrym pomysłem. Próbowałem, ale przypadek testowy pierwotnie wspomniany przez Michaela-Liu wykazał problem:
Podczas gdy IndexOf będzie pasować, istnieje niedopasowanie między długością dopasowania w ciągu źródłowym (1) a oldValue.Length (2). Przejawiało się to przez spowodowanie IndexOutOfRange w niektórych innych rozwiązaniach, gdy oldValue.Length został dodany do bieżącej pozycji dopasowania i nie mogłem znaleźć sposobu na obejście tego. Regex i tak nie pasuje do przypadku, więc wybrałem pragmatyczne rozwiązanie polegające na użyciu tylko
StringComparison.OrdinalIgnoreCase
dla mojego rozwiązania.Mój kod jest podobny do innych odpowiedzi, ale moim zdziwieniem jest to, że szukam dopasowania, zanim podejmę trud tworzenia
StringBuilder
. Jeśli nie zostanie znaleziony, można uniknąć potencjalnie dużej alokacji. Kod staje się następniedo{...}while
zamiastwhile{...}
Zrobiłem kilka obszernych testów w stosunku do innych odpowiedzi, które pojawiły się ułamkowo szybciej i zużyły nieco mniej pamięci.
źródło