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

时间:2011-02-16 11:02:20

标签: c# string replace

我有这个字符串:ABCDEFGHIJ

我需要使用字符串ZX

从位置4替换到位置5

它看起来像这样:ABCZXFGHIJ

但不要与string.replace("DE","ZX")一起使用 - 我需要使用位置

我该怎么做?

19 个答案:

答案 0 :(得分:177)

在字符串中添加和删除范围的最简单方法是使用StringBuilder

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

另一种方法是使用String.Substring,但我认为StringBuilder代码更具可读性。

答案 1 :(得分:152)

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

答案 2 :(得分:34)

ReplaceAt(int index,int length,string replace)

这是一个不使用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类不需要初始化,因为它使用更多的基本操作。如果我错了,请纠正我。 :)

答案 3 :(得分:9)

使用String.Substring()(详情here)剪切左侧部分,然后更换,然后右侧部​​分。玩索引,直到你做对了:)

类似的东西:

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

答案 4 :(得分:7)

作为扩展方法。

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

答案 5 :(得分:5)

        string s = "ABCDEFG";
        string t = "st";
        s = s.Remove(4, t.Length);
        s = s.Insert(4, t);

答案 6 :(得分:3)

你可以尝试一下这个链接:

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

答案 7 :(得分:3)

如果字符串包含Unicode字符(如Emojis),则所有其他答案都不起作用,因为Unicode字符的权重大于字符数。

  

示例:表情符号''转换为字节,将相当于2个字符的权重。因此,如果unicode char放在字符串的开头,offset参数将被移位。)

使用this topic,我将StringInfo类扩展为Replace by position,保持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) : ""
        ));
    }
}

答案 8 :(得分:3)

像其他人所提到的那样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次。所以稍微慢了。

答案 9 :(得分:2)

在这篇文章的帮助下,我创建了以下功能并进行了额外的长度检查

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

答案 10 :(得分:2)

又一个

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

答案 11 :(得分:1)

如果您关心性能,那么这里要避免的事情就是分配。而且,如果您使用的是.Net Core 2.1+(或尚未发布的.Net Standard 2.1),则可以使用the string.Create method

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

这种方法比其他方法更难理解,但它是唯一每次调用仅分配一个对象的方法:新创建的字符串。

答案 12 :(得分:0)

最好使用String.substr()

像这样:

ReplString = GivenStr.substr(0, PostostarRelStr)
           + GivenStr(PostostarRelStr, ReplString.lenght());

答案 13 :(得分:0)

我一直在寻找具有以下要求的解决方案:

  1. 仅使用单个单行表达式
  2. 仅使用系统内置方法(没有自定义实现的实用程序)
  3. 解决方案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);
    

    这也没关系。我猜测它不如第一个表现明智(由于不必要的字符串连接)。但过早优化是所有邪恶的根源

    所以选择你最喜欢的那个:)

答案 14 :(得分:0)

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

让我解释一下我的解决方案。
给出了在两个特定位置(“位置4到位置5”)用两个字符“ Z”和“ X”更改字符串的问题说明,要问的是使用位置索引来更改字符串而不是字符串Replace( )方法(可能是因为实际字符串中可能会重复某些字符),我宁愿使用极简方法来实现目标,而不是使用Substring()和字符串Concat()或字符串{{1 }}和Remove()方法。尽管所有这些解决方案都可以达到相同的目的,但是这仅取决于个人选择和采用简约方法解决的哲学。
回到上面提到的解决方案,如果我们仔细查看Insert()string,它们在内部都将给定的字符串视为字符数组。如果我们看一下StringBuilder的实现,它将维护一个类似于“ StringBuilder”的内部变量来捕获给定的字符串。现在,由于这是一个内部变量,因此我们无法直接访问该变量。对于外部世界,为了能够访问和更改该字符数组,internal char[] m_ChunkChars;通过indexer属性将其公开,该属性类似于

StringBuilder

我上面提到的解决方案利用此索引器功能直接更改IMO高效且极简的内部维护字符数组。

顺便说一句;我们可以更详细地重写上面的解决方案,例如

    [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
        }
      }
    }

在这种情况下,我们还要提到在 string myString = "ABCDEFGHIJ"; StringBuilder tempString = new StringBuilder(myString); tempString[3] = 'Z'; tempString[4] = 'X'; string modifiedString = tempString.ToString(); 的情况下,它还具有indexer属性,作为公开其内部字符数组的一种方式,但是在这种情况下,它仅具有Getter属性(而没有Setter),字符串本质上是不可变的。这就是为什么我们需要使用string来更改字符数组的原因。

StringBuilder

最后但并非最不重要的一点是,该解决方案仅最适合此特定问题,在该问题中,要求仅用预先确定的位置索引替换几个字符。当要求更改相当长的字符串(即要更改的字符数很大)时,这可能不是最佳选择。

答案 15 :(得分:0)

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

答案 16 :(得分:0)

这是一个简单的扩展方法:

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

答案 17 :(得分:0)

我这样做

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

答案 18 :(得分:-2)

我相信最简单的方法是:(没有stringbuilder)

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

这是有效的,因为string类型的变量可以被视为char变量数组。 例如,您可以将名称为“myString”的字符串变量的第二个字符称为myString [1]