Czy jest lepszy sposób na zrobienie tego ...
MyString.Trim().Replace("&", "and").Replace(",", "").Replace(" ", " ")
.Replace(" ", "-").Replace("'", "").Replace("/", "").ToLower();
Rozszerzyłem klasę string, aby ograniczyć ją do jednego zadania, ale czy jest szybszy sposób?
public static class StringExtension
{
public static string clean(this string s)
{
return s.Replace("&", "and").Replace(",", "").Replace(" ", " ")
.Replace(" ", "-").Replace("'", "").Replace(".", "")
.Replace("eacute;", "é").ToLower();
}
}
Dla zabawy (i żeby zatrzymać argumenty w komentarzach) podałem streszczenie porównując różne przykłady poniżej.
Opcja wyrażenia regularnego ma straszne wyniki; opcja słownika pojawia się najszybciej; Długa zwojowa wersja wymiany stringbuildera jest nieco szybsza niż krótka ręka.
c#
string
refactoring
immutability
Chris McKee
źródło
źródło
Odpowiedzi:
Szybciej - nie. Bardziej efektywne - tak, jeśli będziesz korzystać z
StringBuilder
zajęć. W przypadku implementacji każda operacja generuje kopię ciągu, który w pewnych okolicznościach może pogorszyć wydajność. Ciągi znaków są niezmiennymi obiektami, więc każda operacja zwraca tylko zmodyfikowaną kopię.Jeśli spodziewasz się, że ta metoda będzie aktywnie wywoływana w wielu
Strings
znaczących długościach, może być lepszym rozwiązaniem „migracja” jej implementacji doStringBuilder
klasy. Dzięki niemu wszelkie modyfikacje są wykonywane bezpośrednio na tej instancji, dzięki czemu oszczędzasz niepotrzebnych operacji kopiowania.public static class StringExtention { public static string clean(this string s) { StringBuilder sb = new StringBuilder (s); sb.Replace("&", "and"); sb.Replace(",", ""); sb.Replace(" ", " "); sb.Replace(" ", "-"); sb.Replace("'", ""); sb.Replace(".", ""); sb.Replace("eacute;", "é"); return sb.ToString().ToLower(); } }
źródło
będzie to bardziej wydajne:
public static class StringExtension { public static string clean(this string s) { return new StringBuilder(s) .Replace("&", "and") .Replace(",", "") .Replace(" ", " ") .Replace(" ", "-") .Replace("'", "") .Replace(".", "") .Replace("eacute;", "é") .ToString() .ToLower(); } }
źródło
Jeśli szukasz po prostu ładnego rozwiązania i nie musisz oszczędzać kilku nanosekund, co powiesz na cukier LINQ?
var input = "test1test2test3"; var replacements = new Dictionary<string, string> { { "1", "*" }, { "2", "_" }, { "3", "&" } }; var output = replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value));
źródło
Może trochę bardziej czytelny?
public static class StringExtension { private static Dictionary<string, string> _replacements = new Dictionary<string, string>(); static StringExtension() { _replacements["&"] = "and"; _replacements[","] = ""; _replacements[" "] = " "; // etc... } public static string clean(this string s) { foreach (string to_replace in _replacements.Keys) { s = s.Replace(to_replace, _replacements[to_replace]); } return s; } }
Dodaj także sugestię New In Town dotyczącą StringBuilder ...
źródło
private static Dictionary<string, string> _replacements = new Dictionary<string, string>() { {"&", "and"}, {",", ""}, {" ", " "} /* etc */ };
List<Tuple<string,string>>
. To również zmienia kolejność zamian jest brana ORAZ nie jest tak szybka jak nps.Replace("a").Replace("b").Replace("c")
. Nie używaj tego!W proponowanych rozwiązaniach jest jedna rzecz, którą można zoptymalizować. Posiadanie wielu wywołań
Replace()
powoduje, że kod wykonuje wiele przejść przez ten sam ciąg. W przypadku bardzo długich łańcuchów rozwiązania mogą być powolne z powodu braku pojemności pamięci podręcznej procesora. Można rozważyć zastąpienie wielu ciągów w jednym przebiegu .źródło
Inną opcją korzystania z linq jest
[TestMethod] public void Test() { var input = "it's worth a lot of money, if you can find a buyer."; var expected = "its worth a lot of money if you can find a buyer"; var removeList = new string[] { ".", ",", "'" }; var result = input; removeList.ToList().ForEach(o => result = result.Replace(o, string.Empty)); Assert.AreEqual(expected, result); }
źródło
var removeList = new List<string> { /*...*/ };
a następnie po prostu zadzwońremoveList.ForEach( /*...*/ );
i uprość swój kod. Zauważ również, że nie daje pełnej odpowiedzi na pytanie, ponieważ wszystkie znalezione ciągi są zastępowaneString.Empty
.Robię coś podobnego, ale w moim przypadku robię serializację / deserializację, więc muszę być w stanie przejść w obu kierunkach. Uważam, że użycie ciągu [] [] działa prawie identycznie jak słownik, łącznie z inicjalizacją, ale można też pójść w innym kierunku, przywracając zamienniki do ich oryginalnych wartości, do czego słownik naprawdę nie jest przystosowany.
Edycja: możesz użyć
Dictionary<Key,List<Values>>
, aby uzyskać taki sam wynik jak ciąg [] []źródło
string input = "it's worth a lot of money, if you can find a buyer."; for (dynamic i = 0, repl = new string[,] { { "'", "''" }, { "money", "$" }, { "find", "locate" } }; i < repl.Length / 2; i++) { input = input.Replace(repl[i, 0], repl[i, 1]); }
źródło