Zastąp ostatnie wystąpienie słowa w ciągu - C #

82

Mam problem polegający na tym, że muszę zamienić ostatnie wystąpienie słowa w ciągu.

Sytuacja: otrzymuję ciąg znaków w tym formacie:

string filePath ="F:/jan11/MFrame/Templates/feb11";

Następnie wymieniam w TnaNameten sposób:

filePath = filePath.Replace(TnaName, ""); // feb11 is TnaName

To działa, ale mam problem, gdy TnaNamejest taki sam jak mój folder name. Kiedy tak się dzieje, otrzymuję następujący ciąg:

F:/feb11/MFrame/Templates/feb11

Teraz zastąpił oba wystąpienia TnaNamez feb11. Czy istnieje sposób, w jaki mogę zamienić tylko ostatnie wystąpienie słowa w moim ciągu?

Uwaga: feb11to TnaName, które pochodzi z innego procesu - to nie jest problem.

Shree
źródło
Czy Twoim jedynym celem jest zastąpienie ostatniej części ścieżki? (czyli od /początku?)
Simon Whitehead,
Nie, nie ostatnia część, tylko ostatnia TnaName, jest więcej na ścieżce, ale generuję tylko próbkę na pytanie. Dzięki.
Shree
1
Czy ten ciąg jest zawsze ścieżką do czegoś? Jeśli tak, rozważ użycie klasy System.IO.Path.
Yuriy Rozhovetskiy
Tak, ciąg zawsze jest drogą do czegoś.
Shree

Odpowiedzi:

178

Oto funkcja zastępująca ostatnie wystąpienie ciągu

public static string ReplaceLastOccurrence(string Source, string Find, string Replace)
{
        int place = Source.LastIndexOf(Find);

        if(place == -1)
           return Source;

        string result = Source.Remove(place, Find.Length).Insert(place, Replace);
        return result;
}
  • Source to ciąg, na którym chcesz wykonać operację.
  • Find to ciąg, który chcesz zamienić.
  • Replace jest ciągiem, którym chcesz go zastąpić.
Behroz Sikander
źródło
Bardzo dziękuję za ogólną funkcję, działa i zgadzam się z @Simon.
Shree
6
uwaga, może nie ma meczu (tj. Place == -1)
Alireza Noori
7
Prawdopodobnie bardziej logiczne jest zwrócenie źródła niż pusty ciąg w przypadku braku dopasowania.
Sasha
2
Powinieneś zwrócić „return Source;” zamiast „return sting.Empty;” ponieważ jego logika nie powiodła się, jeśli nie znaleziono wystąpienia ciągu wyszukiwania.
Jignesh Variya
1
Dodaj to między (i String Source jak w: public static string ReplaceLastOccurance(this string Source...i masz sprytną metodę rozszerzenia, której możesz użyć do zastąpienia ostatniego wystąpienia ciągu dla dowolnego ciągu.
beaudetious
12

Użyj, string.LastIndexOf()aby znaleźć indeks ostatniego wystąpienia ciągu, a następnie użyj podciągu do wyszukania rozwiązania.

Montycarlo
źródło
7

Musisz dokonać wymiany ręcznie:

int i = filePath.LastIndexOf(TnaName);
if (i >= 0)
    filePath = filePath.Substring(0, i) + filePath.Substring(i + TnaName.Length);
Mohammad Dehghan
źródło
3

Nie rozumiem, dlaczego nie można użyć Regex:

public static string RegexReplace(this string source, string pattern, string replacement)
{
  return Regex.Replace(source,pattern, replacement);
}

public static string ReplaceEnd(this string source, string value, string replacement)
{
  return RegexReplace(source, $"{value}$", replacement);
}

public static string RemoveEnd(this string source, string value)
{
  return ReplaceEnd(source, value, string.Empty);
}

Stosowanie:

string filePath ="F:/feb11/MFrame/Templates/feb11";
filePath = filePath.RemoveEnd("feb11"); // F:/feb11/MFrame/Templates/
filePath = filePath.ReplaceEnd("feb11","jan11"); // F:/feb11/MFrame/Templates/jan11
toddmo
źródło
1
Powinieneś mieć wartość Regex.Escape ().
jcox
Masz na myśli return Regex.Replace(Regex.Replace(source),pattern, replacement);,?
toddmo
Załóżmy, że ktoś wywołuje ReplaceEnd („(foobar)”, „)”, „thenewend”). Twoja funkcja zwróci, ponieważ „) $” jest nieprawidłowym wyrażeniem regularnym. To zadziała: zwróć RegexReplace (źródło, Regex.Escape (wartość) + "$", zamiennik); Ta sama historia dla RemoveEnd.
jcox
@jcox, nie mogłem wymyślić, jak uniknąć podwójnego ucieczki, b / c każda funkcja jest publiczna, więc mamy wiele potencjalnych ścieżek wywołań. W moim przypadku nie używałem go do znaków specjalnych, ale widzę twój punkt widzenia.
toddmo
@toddmo Chciałbym, aby ReplaceEnd i RemoveEnd bezpośrednio wywołać Regex.Replace. Chociaż trochę nie na temat; Chciałbym tylko, aby ludzie byli świadomi, że wstrzyknięcie danych wejściowych użytkownika do wzorca regex może być trudne. Podobnie jak w przypadku wstrzykiwania danych wejściowych do XML lub SQL - musi istnieć jakiś mechanizm ucieczki.
jcox,
1

Możesz użyć Pathklasy z System.IOnamepace:

string filePath = "F:/jan11/MFrame/Templates/feb11";

Console.WriteLine(System.IO.Path.GetDirectoryName(filePath));
Yuriy Rozhovetskiy
źródło
0

Rozwiązanie można wdrożyć jeszcze prościej za pomocą jednej linii:

 static string ReplaceLastOccurrence(string str, string toReplace, string replacement)
    {
        return Regex.Replace(str, $@"^(.*){toReplace}(.*?)$", $"$1{replacement}$2");
    }

Niniejszym wykorzystujemy zachłanność operatora wyrażenia regularnego gwiazdką. Funkcja jest używana w następujący sposób:

var s = "F:/feb11/MFrame/Templates/feb11";
var tnaName = "feb11";
var r = ReplaceLastOccurrence(s,tnaName, string.Empty);
MarcBalta
źródło
0
var lastIndex = filePath.LastIndexOf(TnaName);

filePath = filePath.Substring(0, lastIndex);
Kai Hartmann
źródło
2
Chociaż odpowiedzi zawierające tylko kod mogą odpowiedzieć na to pytanie, możesz znacznie poprawić jakość swojej odpowiedzi, dostarczając kontekst dla swojego kodu, powód, dla którego ten kod działa, oraz odniesienia do dokumentacji do dalszego czytania. Od Jak odpowiedzieć : „Zwięzłość jest akceptowalna, ale pełniejsze wyjaśnienia są lepsze”.
Pranav Hosangadi