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.