【问题标题】:How to replace part of string by position?如何按位置替换部分字符串?
【发布时间】:2011-06-28 06:52:12
【问题描述】:

我有这个字符串:ABCDEFGHIJ

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

看起来像这样:ABCZXFGHIJ

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

一起使用

我该怎么做?

【问题讨论】:

  • @TotZam - 请检查日期。 一个比您链接的那个旧。
  • @ToolmakerSteve 我通常看问题和答案的质量,而不是日期,就像here 所说的那样。在这种情况下,我似乎犯了一个错误,点击了错误的一个标记为重复,因为这个问题的质量明显更好,所以我标记了另一个问题。
  • @TotZam - 啊,我不知道那个建议 - 感谢您指出。 (虽然将旧问题报告为新问题的副本令人困惑,但在这种情况下,值得明确解释您将旧问题标记为重复,因为链接的问题有更好的答案。)跨度>

标签: c# string replace


【解决方案1】:
string s = "ABCDEFGH";
s= s.Remove(3, 2).Insert(3, "ZX");

【讨论】:

  • 我更喜欢这个而不是初始化一个新的 StringBuilder(...)。谢谢!
  • 我不知道为什么有人会使用 stringbuilder 进行此操作。这是一个很好的答案
【解决方案2】:

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

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

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

【讨论】:

  • 最好将其包装在扩展方法中:)
  • 为什么在这里使用 StringBuilder?检查 V4Vendetta 的答案,这更具可读性...
  • @Fortega Remove() 和 Insert() 各自创建并返回一个新字符串。 StringBuilder 方法通过在预先分配的内存部分中工作并在其中移动字符来避免这种额外成本。
  • @redcalx 确实如此,但是通过引入 StringBuilder 对象并降低可读性会带来额外的成本
  • 这里使用 StringBuilder 有什么意义,如果您调用 Remove 和 Insert 的方式与 V4Vendetta 相同,但他是直接在字符串上执行的?似乎是多余的代码。
【解决方案3】:

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 类,而且它使用更多基本操作。如果我错了,请纠正我。 :)

【讨论】:

  • 如果字符串长度超过 200 个字符,Stringbuilder 的效率会更高。
  • 没有压力。直接工作。谢谢
【解决方案4】:

使用String.Substring()(详情here)切割左侧部分,然后是您的替换部分,然后是右侧部分。使用索引,直到你做对了:)

类似:

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

【讨论】:

  • 我用上面三个方法(string.Remove/Insert、Stringbuilder.Remove/Insert和Daniel的Substring回答,SubString是最快的方法)创建了三个方法。
【解决方案5】:

如果您关心性能,那么您要避免的事情就是分配。如果您使用的是 .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));
        });
}

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

【讨论】:

    【解决方案6】:

    作为一种扩展方法。

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

    【讨论】:

      【解决方案7】:
              string s = "ABCDEFG";
              string t = "st";
              s = s.Remove(4, t.Length);
              s = s.Insert(4, t);
      

      【讨论】:

      • 这行得通,你可能不想再把t放回去。
      【解决方案8】:

      你可以试试这个链接:

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

      【讨论】:

        【解决方案9】:

        就像其他人提到的那样,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 次的抽动。所以它稍微慢了一点。

        【讨论】:

        • @Aaron.S - 不,它没有。在我的示例中,"ABCDEFGHIJ""ZX" 的长度不同。
        【解决方案10】:

        还有一个

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

        【讨论】:

          【解决方案11】:

          在这篇文章的帮助下,我创建了以下带有额外长度检查的函数

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

          【讨论】:

            【解决方案12】:

            如果字符串包含 Unicode 字符(如表情符号),则所有其他答案都不起作用,因为 Unicode 字符比字符重更多字节。

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

            使用this topic,我将 StringInfo 类扩展为按位置替换,保持尼克米勒算法以避免这种情况:

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

            【讨论】:

            • dotnetfiddle.net/l0dqS5 我无法让其他方法在 Unicode 上失败。请更改小提琴以演示您的用例。对结果非常感兴趣。
            • @MarkusHooge 尝试将 unicode 字符放在字符串的开头,例如:dotnetfiddle.net/3V2K3Y。您会看到只有最后一行运行良好并将 char 放在第 4 位(在另一种情况下,unicode char 需要 2 个字符长度)
            • 你说得对,不清楚。我更新了我的答案以添加更多解释为什么其他答案不起作用
            【解决方案13】:

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

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

            这也可以。我它的效率不如第一个性能明智(由于不必要的字符串连接)。但是过早的优化是万恶之源

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

            【讨论】:

            • 解决方案 2 有效,但需要更正:string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1, oldString.Length-(i+1));跨度>
            • 更好的是,只需string newString = oldStr.Substring(0, i) + c + oldString.Substring(i+1)。默认情况下没有长度,.Substring 只会拉出字符串的其余部分。
            【解决方案14】:
            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; }
            

            最后但并非最不重要的一点是,此解决方案仅最适合此特定问题,其中要求仅用已知位置索引替换少数字符。当要求更改相当长的字符串时,它可能不是最合适的,即要更改的字符数量很大。

            【讨论】:

            • 请编辑您的答案以解释此代码如何回答问题
            【解决方案15】:

            最好使用String.substr()

            像这样:

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

            【讨论】:

              【解决方案16】:
              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);
              

              【讨论】:

                【解决方案17】:

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

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

                【讨论】:

                  【解决方案18】:

                  我这样做

                  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
                  

                  【讨论】:

                    【解决方案19】:

                    假设我们知道要替换的字符串的索引。

                        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
                    

                    【讨论】:

                      【解决方案20】:

                      我相信最简单的方法是这样的:(没有 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]);  
                      }
                      

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

                      【讨论】:

                      • 这只有效,因为在作者的示例string 中,要替换的字符每个只出现一次。如果您针对"DBCDEFGHIE" 运行此程序,那么您将得到"ZBCZXFGHIX",这不是您想要的结果。另外,我不同意这比两年半前发布的其他非StringBuilder 解决方案更简单。
                      猜你喜欢
                      • 2021-09-23
                      • 2016-07-24
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-06-18
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多