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

如何在.NET中通过索引有效地覆盖字符串的某些部分?

  •  3
  • James  · 技术社区  · 14 年前

    我的问题是,我如何才能有效地做到这一点?StringBuilder类具有 方法,但这会每次延长输出字符串,而不是覆盖它。我是否必须使用 字符串生成器[int index] 索引器,这是低效的吗?因为我要这样做很多次,我希望它尽可能快。

    7 回复  |  直到 14 年前
        1
  •  4
  •   Dan Tao    14 年前

    一次只演一个角色可能是你最好的选择。我这么说是因为 Insert Remove StringBuilder 结果导致字符左右移动,就像在任何可变索引集合(如 List<char> .

    也就是说,这是一个很好的扩展方法,让你的生活更轻松的候选人。

    public static StringBuilder ReplaceSubstring(this StringBuilder stringBuilder, int index, string replacement)
    {
        if (index + replacement.Length > stringBuilder.Length)
        {
            // You could throw an exception here, or you could just
            // append to the end of the StringBuilder -- up to you.
            throw new ArgumentOutOfRangeException();
        }
    
        for (int i = 0; i < replacement.Length; ++i)
        {
            stringBuilder[index + i] = replacement[i];
        }
    
        return stringBuilder;
    }
    

    var builder = new StringBuilder("My name is Dan.");
    builder.ReplaceSubstring(11, "Bob");
    
    Console.WriteLine(builder.ToString());
    

    输出:

    My name is Bob.
        2
  •  2
  •   Justin    14 年前

    StringBuilder 类允许您构建可变字符串。尝试使用 Remove 在执行 Insert 字符串拼接 保持相同的容量,不需要在内存中复制字符串。如果您知道字符串将变长,请尝试在调用时将容量设置为更大 New StringBuilder()

        3
  •  1
  •   Valera Kolupaev    14 年前

    只要字符串是不可变的,对它的每次操作都会导致GC加载,甚至是StringBuilder的插入/删除调用。 我将通过插入点剪切源字符串,然后用需要插入的数据“压缩”它。 之后,您可以在列表中连接字符串,以获得结果字符串。

    下面是一个执行split/zip操作的示例代码。

    public class Field
    {
        public int pos { get; set; }
        public int len { get; set; }
        public string value { get; set; }
        public string tag { get; set; }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var source = "You'r order price [price] and qty [qty].";
            var fields = new List<Field>();
            fields.Add(new Field()
            {
                pos = 18, 
                len = 7, 
                value = "15.99$",
                tag = "price"
            });
            fields.Add(new Field()
            {
                pos = 37-3,
                len = 5,
                value = "7",
                tag = "qty"
            });
            Console.WriteLine(Zip(Split(source, fields), fields));
            Console.WriteLine(ReplaceRegex(source, fields));
    
        }
    
        static IEnumerable<string> Split(string source, IEnumerable<Field> fields)
        {
            var index = 0;
            foreach (var field in fields.OrderBy(q => q.pos))
            {
                yield return source.Substring(index, field.pos - index);
                index = field.pos + field.len;
            }
            yield return source.Substring(index, source.Length - index);
        }
        static string Zip(IEnumerable<string> splitted, IEnumerable<Field> fields)
        {
            var items = splitted.Zip(fields, (l, r) => new string[] { l, r.value }).SelectMany(q => q).ToList();
            items.Add(splitted.Last());
            return string.Concat(items);
        }
        static string ReplaceRegex(string source, IEnumerable<Field> fields)
        {
            var fieldsDict = fields.ToDictionary(q => q.tag);
            var re = new Regex(@"\[(\w+)\]");
            return re.Replace(source, new MatchEvaluator((m) => fieldsDict[m.Groups[1].Value].value));
        }
    }
    

    顺便说一句,最好用regex替换特殊的用户标记,比如[price],[qty]?

        4
  •  0
  •   Jerod Houghtelling    14 年前

    我建议使用 StringBuilder 班级。不过,你可以用一个字符串,但也可能有副作用。下面是一些博客文章,展示了如何操作字符串和可能的副作用。

    http://philosopherdeveloper.wordpress.com/2010/05/28/are-strings-really-immutable-in-net/

    http://philosopherdeveloper.wordpress.com/2010/06/13/string-manipulation-in-net-epilogue-plus-new-theme/

        5
  •  0
  •   Joe    14 年前

    class DataLine
    {
        public string Field1;
        public string Field2;
        public string Field3;
    
        public string OutputDataLine()
        {
            return Field1 + Field2 + Field3;
        }
    }
    

    这是一个简单的静态示例,但我确信它可以变得更通用,这样,如果每个用户定义的字段不同,您就可以处理它。在将数据分解为字段之后,如果仍然需要修改字段中的单个字符,那么至少不会涉及整个数据集。

    现在,这可能会给OutputDataLine函数带来瓶颈,具体取决于您对数据所做的操作。但如果有必要,可以分开处理。

        6
  •  0
  •   HaxElit    14 年前

    public StringBuilder Replace(string oldValue, string newValue, int startIndex, int count)
    

    只需将start index和count设置为1,就可以替换该特定实例。

    你可以做的另一件事就是String.Format(). 将所有预定义字段转换为索引,这样您就可以得到一个类似“This{0}is very{1}”的字符串,然后只需将参数与特定索引匹配并执行String.Format(myString,myParams);

    -劳尔

        7
  •  0
  •   Sergey    8 年前


    因此,我为我的项目创建了Overwrite扩展方法,如下所示。

        public static void Overwrite( this StringBuilder sb, int index, string value )
        {
            int len = Math.Min( value.Length, sb.Length - index );
            sb.Remove( index, len );
            sb.Insert( index, value.Substring( 0, len ) );
        }