代码之家  ›  专栏  ›  技术社区  ›  Robben_Ford_Fan_boy

在C中编辑字符串中的字符#

  •  12
  • Robben_Ford_Fan_boy  · 技术社区  · 14 年前

    用C编辑字符串中的字符最干净的方法是什么?

    C++中的这个C等价物是什么?

    std::string myString = "boom";
    myString[0] = "d";
    
    11 回复  |  直到 14 年前
        1
  •  15
  •   hemp    14 年前

    决定对我感觉到的两种最规范的方法,加上一种我认为是未呈现的方法进行计时;下面是我发现的(发布构建):

    ReplaceAtChars: 86ms
    ReplaceAtSubstring: 258ms
    ReplaceAtStringBuilder: 161ms

    显然,char数组方法是目前为止运行时优化的最佳方法。这实际上表明电流 主要的 答案(StringBuilder)可能不是 最好的 回答。

    下面是我使用的测试:

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("ReplaceAtChars: " + new Stopwatch().Time(() => "test".ReplaceAtChars(1, 'E').ReplaceAtChars(3, 'T'), 1000000) + "ms");
            Console.WriteLine("ReplaceAtSubstring: " + new Stopwatch().Time(() => "test".ReplaceAtSubstring(1, 'E').ReplaceAtSubstring(3, 'T'), 1000000) + "ms");
            Console.WriteLine("ReplaceAtStringBuilder: " + new Stopwatch().Time(() => "test".ReplaceAtStringBuilder(1, 'E').ReplaceAtStringBuilder(3, 'T'), 1000000) + "ms");
        }
    }
    
    public static class ReplaceAtExtensions
    {
        public static string ReplaceAtChars(this string source, int index, char replacement)
        {
            var temp = source.ToCharArray();
            temp[index] = replacement;
            return new String(temp);
        }
    
        public static string ReplaceAtStringBuilder(this string source, int index, char replacement)
        {
            var sb = new StringBuilder(source);
            sb[index] = replacement;
            return sb.ToString();
        }
    
        public static string ReplaceAtSubstring(this string source, int index, char replacement)
        {
            return source.Substring(0, index) + replacement + source.Substring(index + 1);
        }
    }
    
    public static class StopwatchExtensions
    {
        public static long Time(this Stopwatch sw, Action action, int iterations)
        {
            sw.Reset();
            sw.Start();
            for (int i = 0; i < iterations; i++)
            {
                action();
            }
            sw.Stop();
    
            return sw.ElapsedMilliseconds;
        }
    }
    
        2
  •  30
  •   Brian R. Bondy    14 年前

    使用A StringBuilder 相反。

    string is immutable as described by MSDN :

    字符串是不可变的--的内容 不能更改字符串对象 创建对象之后,尽管 语法使它看起来像 可以做到这一点。

    所以你需要这样的东西:

     StringBuilder sb = new StringBuilder("Bello World!");
     sb[0] = 'H';
     string str = sb.ToString();
    
        3
  •  8
  •   Joel Coehoorn    14 年前

    .NET中的字符串是不可变的。那意味着你 不能 编辑它们。你所能做的就是做新的。你必须这样做:

    string myString = "boom";
    myString = "d" + myString.Substring(1);
    
        4
  •  8
  •   corsiKa    14 年前

    字符串是不可变的,所以不能只更改它。

    您可以从字符串中获取char[],进行更改,并从更改后的数组中创建新的字符串。

    您可以使用诸如replace之类的东西,尽管它们不允许您像c一样控制每字符的基础。它们还将在每次更改时生成一个新字符串,其中char[]样式允许您进行所有更改,然后从中生成一个新字符串。

        5
  •  5
  •   Justin Niessner    14 年前

    不能,因为字符串是不可变的。

    您可以随时滚动自己的扩展方法来执行类似的操作:

    public static string ReplaceAtIndex(this string original, 
        int index, char character)
    {
        char[] temp = original.ToCharArray();
        temp[index] = character;
        return new String(temp);
    }
    

    就像这样称呼它:

    string newString = myString.ReplaceAtIndex(0, 'd');
    
        6
  •  4
  •   Toby    14 年前

    如布莱恩所说,使用 StringBuilder 取而代之的是:

    string myString = "boom";
    StringBuilder myStringBuilder = new StringBuilder(myString);
    myStringBuilder[0] = 'd';
    // Whatever else you're going to do to it
    

    每当您再次需要字符串时,请调用 myStringBuilder.ToString()

        7
  •  3
  •   Tesserex    14 年前
    string myString = "boom";
    char[] arr = myString.ToCharArray();
    arr[0] = 'd';
    myString = new String(arr);
    
        8
  •  3
  •   Marc Tidd    14 年前
    string myString = "boom";
    char[] myChars = myString.ToCharArray();
    myChars[0] = 'd';
    myString = new String(myChars);
    
        9
  •  2
  •   hemp    14 年前

    这是我放在一起的一个有趣的。现在,请记住这不是很有效,特别是对于简单的替换。然而,编写并使用相当可读的使用模式是很有趣的。它还强调了一个鲜为人知的事实,即字符串实现了IEnumerable。

    public static class LinqToStrings
    {
        public static IQueryable<char> LinqReplace(this string source, int startIndex, int length, string replacement)
        {
            var querySource = source.AsQueryable();
            return querySource.LinqReplace(startIndex, length, replacement);
        }
    
        public static IQueryable<char> LinqReplace(this IQueryable<char> source, int startIndex, int length, string replacement)
        {
            var querySource = source.AsQueryable();
            return querySource.Take(startIndex).Concat(replacement).Concat(querySource.Skip(startIndex + length));
        }
    
        public static string AsString(this IQueryable<char> source)
        {
            return new string(source.ToArray());
        }
    }
    

    下面是一些示例用法:

    public void test()
    {
        var test = "test";
        Console.WriteLine("Old: " + test);
        Console.WriteLine("New: " + test.LinqReplace(0, 4, "SOMEPIG")
                                        .LinqReplace(4, 0, "terrific")
                                        .AsString());
    }
    

    输出:

    Old: test
    New: SOMEterrificPIG

    同样的方法的另一个版本(速度并不是那么慢)是直接使用子字符串:

    public static string ReplaceAt(this string source, int startIndex, int length, string replacement)
    {
        return source.Substring(0, startIndex) + replacement + source.Substring(startIndex + length);
    }
    

    在一个很好的例子中,你为什么要分析你的代码,为什么你可能应该 在生产代码中使用我的LinqToStrings实现,这里有一个计时测试:

    Console.WriteLine("Using LinqToStrings: " + new Stopwatch().Time(() => "test".LinqReplace(0, 4, "SOMEPIG").LinqReplace(4, 0, "terrific").AsString(), 1000));
    Console.WriteLine("Using Substrings: " + new Stopwatch().Time(() => "test".ReplaceAt(0, 4, "SOMEPIG").ReplaceAt(4, 0, "terrific"), 1000));
    

    它在1000次迭代中测量计时器计时周期,生成以下输出:

    Using LinqToStrings: 3,818,953
    Using Substrings: 1,157
    
        10
  •  2
  •   ravibhagw    14 年前

    字符串在C中是不可变的。使用StringBuilder类或字符数组。

    StringBuilder sb = new StringBuilder("boom");
    sb[0] = 'd';
    

    IIRC,.NET使用所谓的字符串池。每次创建新的字符串文字时,它都作为字符串池的一部分存储在内存中。如果创建与字符串池中的字符串匹配的第二个字符串,两个变量将引用相同的内存。

    当您尝试执行类似于在.NET中使用字符串将“b”字符替换为“d”字符的操作时,您的程序实际上正在字符串池中创建第二个值为“doom”的字符串,但从您的角度看,它似乎根本没有发生这种情况。通过读取代码,我们可以假定字符被替换。

    我提出这个问题是因为我经常遇到这个问题,人们经常问,当一个字符串可以做同样的事情时,为什么他们应该使用StringBuilder。从技术上讲,它不能,但它的设计方式似乎可以。

        11
  •  1
  •   Jeremy Morgan    14 年前

    尝试使用string.replace

    http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx

    可能是你最干净、最简单的方法。