【问题标题】:How to change 1 char in the string?如何更改字符串中的 1 个字符?
【发布时间】:2012-01-24 12:54:20
【问题描述】:

我有这个代码:

string str = "valta is the best place in the World";

我需要替换第一个符号。当我尝试这个时:

str[0] = 'M';

我收到一个错误。我该怎么做?

【问题讨论】:

  • 无论他遇到什么错误都是好的。字符串是不可变的对象,编译器抱怨该指令是正常的......
  • @Oded - 这不起作用的原因有很多。字符串在 .NET 中是不可变的,这与 Delphi 不同,它可以工作。您不能像这样按索引更改字符串字符。 C# 也没有从字符串到 char 的隐式转换 - 'M' 必须声明为 {char c = 'M'}。
  • @J... - 确实如此。我的评论更多的是关于“如何提出问题”的问题。

标签: c# .net string


【解决方案1】:

字符串是不可变的,这意味着您不能更改字符。相反,您创建了新的字符串。

您的要求可以通过多种方式完成。最合适的解决方案将根据您对原始字符串所做的更改的性质而有所不同。你只改变一个字符吗?需要插入/删除/追加吗?

以下是从现有字符串创建新字符串但首字符不同的几种方法:

str = 'M' + str.Remove(0, 1);

str = 'M' + str.Substring(1);

在上面,新字符串被分配给原始变量str

我想补充一点,其他人展示StringBuilder的答案也非常合适。我不会实例化 StringBuilder 来更改一个字符,但如果需要进行许多更改,StringBuilder 是比我在此过程中创建临时新字符串的示例更好的解决方案。 StringBuilder 提供了一个可变对象,它允许许多更改和/或附加操作。完成更改后,将使用 .ToString() 方法从 StringBuilder 创建一个不可变字符串。您可以继续对StringBuilder 对象进行更改,并根据需要使用.ToString() 创建更多新字符串。

【讨论】:

  • 通过在您的首选方法之前添加此行 if (!string.IsNullOrEmpty(str)) 确保防止出现空异常。
  • 或者。您可以执行str[1..](范围从str 的索引1 到Length)来跳过str 中的第一个字符。我个人觉得范围更容易阅读。
【解决方案2】:

我建议您使用StringBuilder 类,而不是在需要时将其解析为字符串。

System.Text.StringBuilder strBuilder = new System.Text.StringBuilder("valta is the best place in the World");
strBuilder[0] = 'M';
string str=strBuilder.ToString();

您不能以这种方式更改字符串的字符,因为在 C# 中,字符串不是动态的并且是不可变的,而且它的字符是只读的。为了确保在其中尝试使用字符串方法,例如,如果您使用str.ToLower(),它会生成新字符串并且您之前的字符串不会改变。

【讨论】:

    【解决方案3】:

    字符串是不可变的。您可以使用字符串生成器类来提供帮助!:

    string str = "valta is the best place in the World";
    
    StringBuilder strB = new StringBuilder(str);
    
    strB[0] = 'M';
    

    【讨论】:

    • @Bobbity Bob 你能更具体一点,为什么这是不正确的?我认为我没有从字符串生成器中分配回字符串(通过使用它的 ToString 方法)
    • 我不明白我的意思。我刚刚运行了代码,它可以工作。如果你编辑你的答案(比如在某处插入一个空格),我也会投票赞成它。现在看起来很好......
    【解决方案4】:

    虽然它不能准确回答 OP 的问题,但根据您的操作,它可能是一个很好的解决方案。下面将解决我的问题。

    假设您必须对字符串中的各种字符进行大量单独的操作。在进行操作时,不要一直使用字符串,而是使用 char[] 数组。因为你可以这样做:

     char[] array = "valta is the best place in the World".ToCharArray();
    

    然后随心所欲地操作...

     array[0] = "M";
    

    完成后将其转换为字符串并需要将其用作字符串:

    string str = new string(array);
    

    【讨论】:

    • 但是StringBuilder 不是比char[] 更好的选择吗? StringBuilder 具有追加、插入、删除和格式化的方法,而 char[] 将几乎保持固定长度。我想如果我正在处理一个只有单个字符操作的固定长度字符串,我可能会选择char[]
    • 我的情况是固定长度的字符串。所以在我的情况下,我真的只是想要最快的方法来替换一个字符。我没有敲其他方法。只是分享一个对我有用的有效方法。
    • 正是我刚刚需要的,所以还是谢谢你的分享。
    • 好点,char[]StringBuilder 更简单、更直观地完成相关任务。
    【解决方案5】:

    合并 Chuck Norris 的答案与 Paulo Mendonça 的使用扩展方法:

    /// <summary>
    /// Replace a string char at index with another char
    /// </summary>
    /// <param name="text">string to be replaced</param>
    /// <param name="index">position of the char to be replaced</param>
    /// <param name="c">replacement char</param>
    public static string ReplaceAtIndex(this string text, int index, char c)
    {
        var stringBuilder = new StringBuilder(text);
        stringBuilder[index] = c;
        return stringBuilder.ToString();
    }
    

    【讨论】:

      【解决方案6】:

      我做了一个方法来做到这一点

          string test = "Paul";
          test = ReplaceAtIndex(0, 'M', test);
      
          // (...)
      
          static string ReplaceAtIndex(int i, char value, string word)
          {
              char[] letters = word.ToCharArray();
              letters[i] = value;
              return string.Join("", letters);
          }
      

      【讨论】:

      • 你应该做一个扩展方法。
      • 最佳解决方案,因为它可以用于第一个字符以外的情况。其他答案似乎有限。
      【解决方案7】:
      str = "M" + str.Substring(1);
      

      如果您要进行多项此类更改,请使用StringBuilderchar[]

      StringBuilder 变得更快的阈值是在大约 5 个连接或子字符串之后,但请注意 a + "b" + c + d + "e" + f 的分组连接是在单个调用中完成的,"a" + "b" + "c" 的编译类型连接不需要打电话)。

      这样做似乎效率极低,但字符串不能更改这一事实可以带来很多效率提升和其他优势,例如 Why .NET String is immutable? 中提到的

      【讨论】:

        【解决方案8】:

        我在不安全的环境中找到了解决方案:

            string str = "gg"; char c = 'H'; int index = 1;
            fixed (char* arr = str) arr[index] = 'H';
            Console.WriteLine(str);
        

        就是这么简单。 在安全的环境中:

            string str = "gg"; char c = 'H'; int index = 1;
            GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
            IntPtr arrAddress = handle.AddrOfPinnedObject();
            Marshal.WriteInt16(arrAddress + index * sizeof(char), c);
            handle.Free();
            Console.WriteLine(str);
        

        【讨论】:

        • 破坏基本的字符串不可变功能是很奇怪的,因为默认的 C# 开发人员不会期望这样的转变。但是TBH我来这里是为了这种答案(仍然不会在产品中使用它)
        【解决方案9】:

        如果速度很重要,那么您可以这样做:

        String strValue = "$Some String Here!";
        strValue = strValue.Remove(0, 1).Insert(0, "*");
        

        这样,您不会真正重构字符串,而是保留原始对象,只是删除第一个字符并插入一个新字符。

        【讨论】:

          【解决方案10】:

          我通常是这样处理的:

             char[] c = text.ToCharArray();
             for (i=0; i<c.Length; i++)
             {
              if (c[i]>'9' || c[i]<'0') // use any rules of your choice
              {
               c[i]=' '; // put in any character you like
              }
             }
             // the new string can have the same name, or a new variable       
             String text=new string(c); 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-04-02
            • 1970-01-01
            • 2010-11-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多