簡體   English   中英

如何按位置替換部分字符串?

[英]How to replace part of string by position?

我有這個字符串: ABCDEFGHIJ

我需要用字符串ZX從位置 4 替換到位置 5

它看起來像這樣: ABCZXFGHIJ

但不要與string.replace("DE","ZX")一起使用 - 我需要與position一起使用

我該怎么做?

string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");

在字符串中添加和刪除范圍的最簡單方法是使用StringBuilder

var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();

另一種方法是使用String.Substring ,但我認為StringBuilder代碼變得更具可讀性。

ReplaceAt(整數索引,整數長度,字符串替換)

這是一個不使用 StringBuilder 或 Substring 的擴展方法。 此方法還允許替換字符串超出源字符串的長度。

//// str - the source string
//// index- the start location to replace at (0-based)
//// length - the number of characters to be removed before inserting
//// replace - the string that is replacing characters
public static string ReplaceAt(this string str, int index, int length, string replace)
{
    return str.Remove(index, Math.Min(length, str.Length - index))
            .Insert(index, replace);
}

使用此函數時,如果希望整個替換字符串替換盡可能多的字符,則將 length 設置為替換字符串的長度:

"0123456789".ReplaceAt(7, 5, "Hello") = "0123456Hello"

否則,您可以指定要刪除的字符數:

"0123456789".ReplaceAt(2, 2, "Hello") = "01Hello456789"

如果將長度指定為 0,則此函數的作用類似於插入函數:

"0123456789".ReplaceAt(4, 0, "Hello") = "0123Hello456789"

我想這更有效,因為不需要初始化 StringBuilder 類並且因為它使用更多基本操作。 如果我錯了,請糾正我。 :)

使用String.Substring() (詳見此處)切割左側部分,然后是您的替換部分,然后是右側部分。 玩索引,直到你做對了:)

就像是:

string replacement=original.Substring(0,start)+
    rep+original.Substring(start+rep.Length);

如果您關心性能,那么您要避免的事情就是分配。 如果您使用的是 .Net Core 2.1+(或尚未發布的 .Net Standard 2.1),那么您可以使用string.Create方法

public static string ReplaceAt(this string str, int index, int length, string replace)
{
    return string.Create(str.Length - length + replace.Length, (str, index, length, replace),
        (span, state) =>
        {
            state.str.AsSpan().Slice(0, state.index).CopyTo(span);
            state.replace.AsSpan().CopyTo(span.Slice(state.index));
            state.str.AsSpan().Slice(state.index + state.length).CopyTo(span.Slice(state.index + state.replace.Length));
        });
}

這種方法比其他方法更難理解,但它是唯一一種每次調用只分配一個對象:新創建的字符串。

作為一種擴展方法。

public static class StringBuilderExtension
{
    public static string SubsituteString(this string OriginalStr, int index, int length, string SubsituteStr)
    {
        return new StringBuilder(OriginalStr).Remove(index, length).Insert(index, SubsituteStr).ToString();
    }
}
        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);

就像其他人提到的那樣, Substring()函數的存在是有原因的:

static void Main(string[] args)
{
    string input = "ABCDEFGHIJ";

    string output = input.Overwrite(3, "ZX"); // 4th position has index 3
    // ABCZXFGHIJ
}

public static string Overwrite(this string text, int position, string new_text)
{
    return text.Substring(0, position) + new_text + text.Substring(position + new_text.Length);
}

此外,我針對StringBuilder解決方案對此進行了計時,得到了 900 次抽動與 875 次。所以它稍微慢了一點。

完后還有

    public static string ReplaceAtPosition(this string self, int position, string newValue)        
    {
        return self.Remove(position, newValue.Length).Insert(position, newValue); 
    }

你可以試試這個鏈接:

string str = "ABCDEFGHIJ";
str = str.Substring(0, 2) + "ZX" + str.Substring(5);

在這篇文章的幫助下,我創建了以下帶有額外長度檢查的函數

public string ReplaceStringByIndex(string original, string replaceWith, int replaceIndex)
{
    if (original.Length >= (replaceIndex + replaceWith.Length))
    {
        StringBuilder rev = new StringBuilder(original);
        rev.Remove(replaceIndex, replaceWith.Length);
        rev.Insert(replaceIndex, replaceWith);
        return rev.ToString();
    }
    else
    {
        throw new Exception("Wrong lengths for the operation");
    }
}

如果字符串包含 Unicode 字符(如 Emojis),則所有其他答案都不起作用,因為 Unicode 字符比字符權重更多字節。

示例:表情符號 '🎶' 轉換為字節,其權重相當於 2 個字符。 因此,如果將 unicode char 放在字符串的開頭,則offset參數將被移動)。

有了這個主題,我將 StringInfo 類擴展為通過保持 Nick Miller 算法的位置來替換以避免這種情況:

public static class StringInfoUtils
{
    public static string ReplaceByPosition(this string str, string replaceBy, int offset, int count)
    {
        return new StringInfo(str).ReplaceByPosition(replaceBy, offset, count).String;
    }

    public static StringInfo ReplaceByPosition(this StringInfo str, string replaceBy, int offset, int count)
    {
        return str.RemoveByTextElements(offset, count).InsertByTextElements(offset, replaceBy);
    }

    public static StringInfo RemoveByTextElements(this StringInfo str, int offset, int count)
    {
        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            offset + count < str.LengthInTextElements
                ? str.SubstringByTextElements(offset + count, str.LengthInTextElements - count - offset)
                : ""
            ));
    }
    public static StringInfo InsertByTextElements(this StringInfo str, int offset, string insertStr)
    {
        if (string.IsNullOrEmpty(str?.String))
            return new StringInfo(insertStr);
        return new StringInfo(string.Concat(
            str.SubstringByTextElements(0, offset),
            insertStr,
            str.LengthInTextElements - offset > 0 ? str.SubstringByTextElements(offset, str.LengthInTextElements - offset) : ""
        ));
    }
}

我正在尋找具有以下要求的解決方案:

  1. 僅使用一個單行表達式
  2. 僅使用系統內置方法(沒有自定義實現的實用程序)

解決方案 1

最適合我的解決方案是:

// replace `oldString[i]` with `c`
string newString = new StringBuilder(oldString).Replace(oldString[i], c, i, 1).ToString();

這使用StringBuilder.Replace(oldChar, newChar, position, count)

解決方案 2

滿足我要求的另一個解決方案是使用帶有連接的Substring

string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length);

這也可以。 它的效率不如第一個性能明智(由於不必要的字符串連接)。 過早的優化是萬惡之源

所以選擇你最喜歡的一個:)

string myString = "ABCDEFGHIJ";
string modifiedString = new StringBuilder(myString){[3]='Z', [4]='X'}.ToString();

讓我解釋一下我的解決方案。
鑒於使用兩個字符'Z'和'X'在其兩個特定位置(“位置4到位置5”)更改字符串的問題陳述,並且要求使用位置索引來更改字符串而不是字符串替換( ) 方法(可能是因為實際字符串中某些字符可能重復),我寧願使用極簡方法來實現目標,而不是使用Substring()和字符串Concat()或字符串Remove()Insert()方法。 盡管所有這些解決方案都將達到相同目標的目的,但這僅取決於個人選擇和以極簡主義方法解決的理念。
回到我上面提到的解決方案,如果我們仔細看看stringStringBuilder ,它們都會在內部將給定的字符串視為字符數組。 如果我們看一下StringBuilder的實現,它會維護一個內部變量,例如“ internal char[] m_ChunkChars; ” 來捕獲給定的字符串。 現在由於這是一個內部變量,我們不能直接訪問它。 對於外部世界,為了能夠訪問和更改該字符數組, StringBuilder通過 indexer 屬性公開它們,如下所示

    [IndexerName("Chars")]
    public char this[int index]
    {
      get
      {
        StringBuilder stringBuilder = this;
        do
        {
          // … some code
            return stringBuilder.m_ChunkChars[index1];
          // … some more code
        }
      }
      set
      {
        StringBuilder stringBuilder = this;
        do
        {
            //… some code
            stringBuilder.m_ChunkChars[index1] = value;
            return;
            // …. Some more code
        }
      }
    }

我上面提到的解決方案利用此索引器功能直接更改 IMO 高效且極簡的內部維護的字符數組。

順便提一句; 我們可以更詳細地重寫上述解決方案,如下所示

 string myString = "ABCDEFGHIJ";
 StringBuilder tempString = new StringBuilder(myString);
 tempString[3] = 'Z';
 tempString[4] = 'X';
 string modifiedString = tempString.ToString();

在這種情況下還想提一下,在string的情況下,它還具有 indexer 屬性作為公開其內部字符數組的一種手段,但在這種情況下,它只有 Getter 屬性(沒有 Setter),因為字符串本質上是不可變的。 這就是為什么我們需要使用StringBuilder來改變字符數組。

[IndexerName("Chars")]
public extern char this[int index] { [SecuritySafeCritical, __DynamicallyInvokable, MethodImpl(MethodImplOptions.InternalCall)] get; }

最后但並非最不重要的一點是,此解決方案僅最適合此特定問題,其中要求僅用已知位置索引替換少數字符。 當要求更改相當長的字符串(即要更改的字符數量很大)時,它可能不是最合適的。

最好使用String.substr()

像這樣:

ReplString = GivenStr.substr(0, PostostarRelStr)
           + GivenStr(PostostarRelStr, ReplString.lenght());
String timestamp = "2019-09-18 21.42.05.000705";
String sub1 = timestamp.substring(0, 19).replace('.', ':'); 
String sub2 = timestamp.substring(19, timestamp.length());
System.out.println("Original String "+ timestamp);      
System.out.println("Replaced Value "+ sub1+sub2);

這是一個簡單的擴展方法:

    public static class StringBuilderExtensions
    {
        public static StringBuilder Replace(this StringBuilder sb, int position, string newString)
            => sb.Replace(position, newString.Length, newString);

        public static StringBuilder Replace(this StringBuilder sb, int position, int length, string newString)
            => (newString.Length <= length)
                ? sb.Remove(position, newString.Length).Insert(position, newString)
                : sb.Remove(position, length).Insert(position, newString.Substring(0, length));
    }

像這樣使用它:

var theString = new string(' ', 10);
var sb = new StringBuilder(theString);
sb.Replace(5, "foo");
return sb.ToString();

我這樣做

Dim QTT As Double
                If IsDBNull(dr.Item(7)) Then
                    QTT = 0
                Else
                    Dim value As String = dr.Item(7).ToString()
                    Dim posicpoint As Integer = value.LastIndexOf(".")
                    If posicpoint > 0 Then
                        Dim v As New Text.StringBuilder(value)
                        v.Remove(posicpoint, 1)
                        v.Insert(posicpoint, ",")
                        QTT = Convert.ToDouble(v.ToString())
                    Else
                        QTT = Convert.ToDouble(dr.Item(7).ToString())
                    End If
                    Console.WriteLine(QTT.ToString())
                End If

假設我們知道要替換的字符串的索引。

    string s = "ABCDEFGDEJ";
    string z = "DE";
    int i = s.IndexOf(z);
    if(i == 3)
        s = s.Remove(3,z.Length).Insert(3,"ZX");
    //s = ABCZXFGDEJ

你好,這段代碼對我有幫助:

var theString = "ABCDEFGHIJ";
var aStringBuilder = new StringBuilder(theString);
aStringBuilder.Remove(3, 2);
aStringBuilder.Insert(3, "ZX");
theString = aStringBuilder.ToString();

我相信最簡單的方法是這樣的:(沒有字符串生成器)

string myString = "ABCDEFGHIJ";
char[] replacementChars = {'Z', 'X'};
byte j = 0;

for (byte i = 3; i <= 4; i++, j++)  
{                   
myString = myString.Replace(myString[i], replacementChars[j]);  
}

這是有效的,因為字符串類型的變量可以被視為 char 變量的數組。 例如,您可以將名稱為“myString”的字符串變量的第二個字符稱為 myString[1]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM