Reemplazar la última aparición de una palabra en una cadena: C #

82

Tengo un problema en el que necesito reemplazar la última aparición de una palabra en una cadena.

Situación: me dan una cadena que tiene este formato:

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

Luego reemplazo TnaNameasí:

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

Esto funciona, pero tengo un problema cuando TnaNamees el mismo que mi folder name. Cuando esto sucede, termino obteniendo una cadena como esta:

F:/feb11/MFrame/Templates/feb11

Ahora ha reemplazado ambas apariciones de TnaNamecon feb11. ¿Hay alguna forma de que pueda reemplazar solo la última aparición de la palabra en mi cadena?

Nota: feb11es lo TnaNameque proviene de otro proceso, eso no es un problema.

Shree
fuente
¿Su único objetivo es reemplazar la última parte del camino? (es decir, ¿de en /adelante?)
Simon Whitehead
No, no una última parte repalce, solo la última, TnaNamehay más en la ruta, pero solo genero una muestra para la pregunta.Gracias.
Shree
1
¿Es esta cadena siempre un camino hacia algo? Considere usar la clase System.IO.Path si lo es.
Yuriy Rozhovetskiy
Sí, cadena siempre un camino hacia algo.
Shree

Respuestas:

176

Aquí está la función para reemplazar la última aparición de una cadena

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 es la cadena en la que desea realizar la operación.
  • Find es la cadena que desea reemplazar.
  • Replace es la cadena con la que desea reemplazarla.
Behroz Sikander
fuente
Muchas gracias por la función genérica, es un trabajo y también estoy de acuerdo con @Simon.
Shree
6
cuidado, tal vez no hay coincidencia (es decir Place == -1)
Alireza Noori
7
Probablemente sea más lógico devolver la fuente que una cadena vacía en caso de que no se encuentre una coincidencia.
Sasha
2
Debería devolver "return Source;" en lugar de "return sting.Empty;" porque su lógica falla si no se encuentra ninguna ocurrencia de la cadena de búsqueda.
Jignesh Variya
1
Agregue esto entre (y la fuente de la cadena como en: public static string ReplaceLastOccurance(this string Source...y tendrá un método de extensión ingenioso que puede usar para reemplazar la última aparición de una cadena para cualquier cadena.
beaudetious
12

Use string.LastIndexOf()para encontrar el índice de la última aparición de la cadena y luego use la subcadena para buscar su solución.

Montycarlo
fuente
7

Tienes que hacer el reemplazo manualmente:

int i = filePath.LastIndexOf(TnaName);
if (i >= 0)
    filePath = filePath.Substring(0, i) + filePath.Substring(i + TnaName.Length);
Mohammad Dehghan
fuente
3

No veo por qué no se puede usar 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);
}

Uso:

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
fuente
1
Debe tener el valor de Regex.Escape ().
jcox
¿Quieres decir return Regex.Replace(Regex.Replace(source),pattern, replacement);?
toddmo
Supongamos que alguien llama a ReplaceEnd ("(foobar)", ")", "thenewend"). Su función arrojará, porque ") $" es una expresión regular no válida. Esto funcionaría: return RegexReplace (fuente, Regex.Escape (valor) + "$", reemplazo); La misma historia para su RemoveEnd.
jcox
@jcox, no pude averiguar cómo evitar el doble escape, porque cada función es pública, por lo que tenemos múltiples rutas de llamadas potenciales. En mi caso, no lo estaba usando para caracteres especiales, pero veo tu punto.
toddmo
@toddmo Haría que ReplaceEnd y RemoveEnd llamaran a Regex.Replace directamente. Un poco fuera de tema, sin embargo; Solo me gustaría que la gente sepa que inyectar la entrada del usuario en un patrón de expresiones regulares puede ser complicado. Similar a inyectar entradas en XML o SQL, debe haber algún mecanismo de escape.
jcox
1

Puede usar una Pathclase del System.IOespacio de nombres:

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

Console.WriteLine(System.IO.Path.GetDirectoryName(filePath));
Yuriy Rozhovetskiy
fuente
0

La solución se puede implementar aún más simple con una sola línea:

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

De este modo, aprovechamos la codicia del operador de asterisco regex. La función se usa así:

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

filePath = filePath.Substring(0, lastIndex);
Kai Hartmann
fuente
2
Si bien las respuestas de solo código pueden responder la pregunta, podría mejorar significativamente la calidad de su respuesta al proporcionar contexto para su código, una razón por la que este código funciona y algunas referencias a la documentación para leer más. De Cómo responder : "La brevedad es aceptable, pero las explicaciones más completas son mejores".
Pranav Hosangadi