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?


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");

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ąć.


1
To działa dosłownie "foo", ale będziesz potrzebować new Regex(Regex.Escape("foo"))przenośnego "foo".
— ruffin


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");

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.


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ę


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);

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

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.


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);

2

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

string result = Microsoft.VisualBasic.Strings.Replace("111", "1", "0", 2, 1); // "101"

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];

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));
    }

-1
string abc = "AAAAX1";

            if(abc.IndexOf("AA") == 0)
            {
                abc.Remove(0, 2);
                abc = "XQ" + abc;
            }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.