Заменить последнее вхождение слова в строке - C #

82

У меня проблема, когда мне нужно заменить последнее вхождение слова в строке.

Ситуация: мне дана строка в следующем формате:

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

Затем я заменяю TnaNameвот так:

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

Это работает, но у меня проблема, когда TnaNameон такой же, как мой folder name. Когда это происходит, я получаю такую ​​строку:

F:/feb11/MFrame/Templates/feb11

Теперь он заменил оба вхождения TnaNameс feb11. Есть ли способ заменить только последнее вхождение слова в строке?

Примечание: feb11это TnaNameрезультат другого процесса - это не проблема.

Шри
источник
Ваша единственная цель - заменить последнюю часть пути? (то есть, начиная с этого /момента?)
Саймон Уайтхед,
Нет, не последняя часть, только последняя, TnaNameв пути больше, но я генерирую только образец для вопроса. Спасибо .
Shree
1
Всегда ли эта строка является путем к чему-то? Рассмотрите возможность использования класса System.IO.Path, если это так.
Юрий Рожовецкий
Да нить всегда путь к чему-то.
Shree

Ответы:

179

Вот функция для замены последнего вхождения строки

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 - строка, над которой вы хотите выполнить операцию.
  • Find это строка, которую вы хотите заменить.
  • Replace - это строка, которой вы хотите ее заменить.
Бехроз Сикандер
источник
Большое спасибо за универсальную функцию, она работает, и я также согласен с @Simon.
Shree
6
будьте осторожны, возможно, нет совпадения (т.е. Place == -1)
Алиреза Нури
7
Вероятно, логичнее вернуть источник, чем пустую строку, если совпадение не найдено.
Саша
2
Вы должны вернуть "return Source;" вместо "return sting.Empty;" потому что его логический сбой, если не найдено вхождение строки поиска.
Jignesh Variya
1
Добавьте это между (и источником строки, как в: public static string ReplaceLastOccurance(this string Source...и у вас есть отличный метод расширения, который вы можете использовать для замены последнего вхождения строки для любой строки.
красиво
12

Используйте string.LastIndexOf()для поиска индекса последнего вхождения строки, а затем используйте подстроку для поиска решения.

Монтикарло
источник
7

Вам необходимо произвести замену вручную:

int i = filePath.LastIndexOf(TnaName);
if (i >= 0)
    filePath = filePath.Substring(0, i) + filePath.Substring(i + TnaName.Length);
Мохаммад Дехган
источник
3

Я не понимаю, почему нельзя использовать 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);
}

Применение:

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
источник
1
Вам следует указать значение Regex.Escape ().
jcox
Вы имеете в виду return Regex.Replace(Regex.Replace(source),pattern, replacement);?
toddmo
Предположим, кто-то вызывает ReplaceEnd ("(foobar)", ")", "thenewend"). Ваша функция выдаст ошибку, потому что ") $" является недопустимым регулярным выражением. Это сработает: return RegexReplace (источник, Regex.Escape (значение) + «$», замена); Та же история и с вашим RemoveEnd.
jcox
@jcox, я не мог понять, как избежать двойного экранирования, b / c каждая функция является общедоступной, поэтому у нас есть несколько потенциальных путей вызова. В моем случае я не использовал его для специальных символов, но я понимаю вашу точку зрения.
toddmo 06
@toddmo Я бы хотел, чтобы ReplaceEnd и RemoveEnd вызывали Regex.Replace напрямую. Хотя вроде как не по теме; Я просто хочу, чтобы люди знали, что введение пользовательского ввода в шаблон регулярного выражения может быть сложным. Подобно введению ввода в XML или SQL - должен быть какой-то механизм выхода.
jcox
1

Вы можете использовать Pathкласс из System.IOпространства имен:

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

Console.WriteLine(System.IO.Path.GetDirectoryName(filePath));
Юрий Рожовецкий
источник
0

Решение можно реализовать еще проще с помощью одной строчки:

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

Таким образом, мы воспользовались жадностью оператора звездочки регулярного выражения. Функция используется так:

var s = "F:/feb11/MFrame/Templates/feb11";
var tnaName = "feb11";
var r = ReplaceLastOccurrence(s,tnaName, string.Empty);
Марк Балта
источник
0
var lastIndex = filePath.LastIndexOf(TnaName);

filePath = filePath.Substring(0, lastIndex);
Кай Хартманн
источник
2
Хотя ответы только на код могут ответить на вопрос, вы можете значительно улучшить качество своего ответа, предоставив контекст для своего кода, причину, почему этот код работает, и некоторые ссылки на документацию для дальнейшего чтения. От Как к ответу : «Краткость приемлема, но более полные объяснения лучше».
Пранав Хосангади,