Jak zamienić * pierwsze wystąpienie * ciągu w .NET?

108

Chcę zamienić pierwsze wystąpienie w danym ciągu.

Jak mogę to osiągnąć w .NET?

Żegnaj StackExchange
źródło
Prosimy o jasne posty, które ludzie mogą zrozumieć. Też dla ciebie zredagowałem. Powinieneś był określić język przynajmniej tutaj.
GEOCHET
Oczywiście nigdy nie jest zastępowany ... zawsze jest to nowy ciąg zawierający oryginalny tekst z zastąpionym tekstem. Dzieje się tak, ponieważ ciąg jest niezmienny.
Pablo Marambio
Wypróbowałem metodę `String.Replace ()`. ale zamienia wszystkie „AA” na „XQ”
Thorin Oakenshield
2
to pytanie - stackoverflow.com/questions/141045/… - ujawnia wszystko, co musisz zrobić
stack72
1
Uwaga: połączenie z innym podobnym pytaniem, w którym użyto „AA” => „XQ” jako przykładów do znalezienia / zastąpienia.
Marc Gravell

Odpowiedzi:

134
string ReplaceFirst(string text, string search, string replace)
{
  int pos = text.IndexOf(search);
  if (pos < 0)
  {
    return text;
  }
  return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}

Przykład:

string str = "The brown brown fox jumps over the lazy dog";

str = ReplaceFirst(str, "brown", "quick");

EDYCJA : Jak wspomniano @itsmatt , istnieje również Regex.Replace (String, String, Int32), który może zrobić to samo, ale prawdopodobnie jest droższy w czasie wykonywania, ponieważ wykorzystuje w pełni funkcjonalny parser, w którym moja metoda wykonuje jedno wyszukiwanie i trzy ciągi konkatenacje.

EDIT2 : Jeśli jest to typowe zadanie, możesz chcieć uczynić tę metodę metodą rozszerzającą:

public static class StringExtension
{
  public static string ReplaceFirst(this string text, string search, string replace)
  {
     // ...same as above...
  }
}

Korzystając z powyższego przykładu można teraz napisać:

str = str.ReplaceFirst("brown", "quick");
VVS
źródło
2
Ciekawe, czy przetestowałeś swoje założenie, że podejście regex jest droższe w czasie wykonywania? A co z prędkością? Być może wyszukiwanie przy użyciu Regex jest szybsze niż przy użyciu IndexOf?
mfloryan,
Wolę odpowiedź @BilltheLizard obejmującą Remove () i Insert () zamiast tego podejścia z użyciem Substring (). Czy istnieją podstawy, by twierdzić, że jeden jest lepszy od drugiego?
JohnC
3
Uwaga: nie działa to poprawnie w przypadku łączenia znaków lub ligatur w standardzie Unicode. Na przykład ReplaceFirst("oef", "œ", "i")niepoprawnie zwraca „ief” zamiast „if”. Zobacz to pytanie, aby uzyskać więcej informacji.
Michael Liu
2
ReSharper ostrzega String.IndexOf is culture specific.. Bardziej niezawodny do aktualizacji int pos = text.IndexOf(search, StringComparison.Ordinal);.
Contango
64

Jak powiedział itsmatt , Regex.Replace to dobry wybór, jednak aby jego odpowiedź była bardziej kompletna, uzupełnię ją przykładowym kodem:

using System.Text.RegularExpressions;
...
Regex regex = new Regex("foo");
string result = regex.Replace("foo1 foo2 foo3 foo4", "bar", 1);             
// result = "bar1 foo2 foo3 foo4"

Trzeci parametr, w tym przypadku ustawiony na 1, to liczba wystąpień wzorca wyrażenia regularnego, który chcesz zamienić w ciągu wejściowym od początku ciągu.

Miałem nadzieję, że można to zrobić za pomocą statycznego przeciążenia Regex.Replace, ale niestety wygląda na to, że potrzebujesz instancji Regex, aby to osiągnąć.

Wes Haggard
źródło
1
To działa dosłownie "foo", ale będziesz potrzebować new Regex(Regex.Escape("foo"))przenośnego "foo".
ruffin
17

Spójrz na Regex.Replace .

itsmatt
źródło
2
W szczególności metoda Regex.Replace (String, String, Int32) załatwi sprawę i jest naprawdę zwięzła.
itsmatt
15

Biorąc pod uwagę „tylko pierwszy”, być może:

int index = input.IndexOf("AA");
if (index >= 0) output = input.Substring(0, index) + "XQ" +
     input.Substring(index + 2);

?

Lub bardziej ogólnie:

public static string ReplaceFirstInstance(this string source,
    string find, string replace)
{
    int index = source.IndexOf(find);
    return index < 0 ? source : source.Substring(0, index) + replace +
         source.Substring(index + find.Length);
}

Następnie:

string output = input.ReplaceFirstInstance("AA", "XQ");
Marc Gravell
źródło
11
using System.Text.RegularExpressions;

RegEx MyRegEx = new RegEx("F");
string result = MyRegex.Replace(InputString, "R", 1);

znajdzie pierwszy Fw InputStringi zastąpi go R.

Deenesh
źródło
2
Uprościłem to do jednej result = (New Regex("F")).Replace(InputString, "R", 1)
linijki
Najlepsza odpowiedź tutaj (w połączeniu z cjbarth)
Todd Vance
8

Metoda rozszerzenia C #, która zrobi to:

public static class StringExt
{
    public static string ReplaceFirstOccurrence(this string s, string oldValue, string newValue)
    {
         int i = s.IndexOf(oldValue);
         return s.Remove(i, oldValue.Length).Insert(i, newValue);    
    } 
}

Cieszyć się

mortenbpost
źródło
Dzięki! Zmodyfikowałem to, aby utworzyć metodę rozszerzenia „RemoveFirst”, która… usuwa pierwsze wystąpienie znaku z ciągu.
pbh101
4
To się nie powiedzie, jeśli oldValue nie jest częścią ciągu.
VVS
8

W składni C #:

int loc = original.IndexOf(oldValue);
if( loc < 0 ) {
    return original;
}
return original.Remove(loc, oldValue.Length).Insert(loc, newValue);
Bill the Lizard
źródło
4

A ponieważ do rozważenia jest również VB.NET, chciałbym zaoferować:

Private Function ReplaceFirst(ByVal text As String, ByVal search As String, ByVal replace As String) As String
    Dim pos As Integer = text.IndexOf(search)
    If pos >= 0 Then
        Return text.Substring(0, pos) + replace + text.Substring(pos + search.Length)
    End If
    Return text 
End Function
Anthony Potts
źródło
4

Zakłada, że AAnależy wymienić tylko wtedy, gdy znajduje się na samym początku ciągu:

var newString;
if(myString.StartsWith("AA"))
{
  newString ="XQ" + myString.Substring(2);
}

Jeśli chcesz zamienić pierwsze wystąpienie AA, niezależnie od tego, czy ciąg zaczyna się od niego, czy nie, skorzystaj z rozwiązania od Marca.

Oded
źródło
3

Jedno z przeciążeń funkcji Regex.Replacetrwa int„Maksymalna liczba przypadków zastąpienia”. Oczywiście używanie Regex.Replacedo zamiany zwykłego tekstu może wydawać się przesadą, ale z pewnością jest zwięzłe:

string output = (new Regex("AA")).Replace(input, "XQ", 1);
AakashM
źródło
2

Dla każdego, komu nie przeszkadza odniesienie Microsoft.VisualBasic, istnieje Replacemetoda :

string result = Microsoft.VisualBasic.Strings.Replace("111", "1", "0", 2, 1); // "101"
Slai
źródło
1

Ten przykład usuwa podciągi (ale jest wolniejszy), ale prawdopodobnie jest znacznie szybszy niż wyrażenie regularne:

var parts = contents.ToString().Split(new string[] { "needle" }, 2, StringSplitOptions.None);
return parts[0] + "replacement" + parts[1];

źródło
0

Zaktualizowana metoda rozszerzenia wykorzystująca Spando zminimalizowania tworzenia nowych ciągów

    public static string ReplaceFirstOccurrence(this string source, string search, string replace) {
        int index = source.IndexOf(search);
        if (index < 0) return source;
        var sourceSpan = source.AsSpan();
        return string.Concat(sourceSpan.Slice(0, index), replace, sourceSpan.Slice(index + search.Length));
    }
Brad Patton
źródło
-1
string abc = "AAAAX1";

            if(abc.IndexOf("AA") == 0)
            {
                abc.Remove(0, 2);
                abc = "XQ" + abc;
            }

źródło