根据一些映射的子字符串替换

时间:2014-03-09 14:47:06

标签: c# string stringbuilder

给定一个字符串,我需要根据给定的映射替换子字符串。映射确定替换的开始位置,要替换的文本长度和替换字符串。映射根据以下方案:

public struct mapItem
{
    public int offset;
    public int length;
    public string newString;
}

例如:给定映射{{0,3,"frog"},{9,3,"kva"}}和字符串

"dog says gav"

我们从位置0开始将长度为3的子串替换为“青蛙”,即

dog - > frog

并从位置9开始长度为3的子串到“kva”,即

gav->kva

新字符串变为:

"frog says kva"

我怎样才能有效地做到这一点?

2 个答案:

答案 0 :(得分:2)

您必须注意替换考虑到之前替换产生的转变。使用StringBuilder也更有效,因为不会像string操作那样在每个操作中分配新内存。 (字符串是不变的,这意味着在每个字符串操作中都会创建一个全新的字符串。)

var maps = new List<MapItem> { ... };
var sb = new StringBuilder("dog says gav");
int shift = 0;
foreach (MapItem map in maps.OrderBy(m => m.Offset)) {
    sb.Remove(map.Offset + shift, map.Length);
    sb.Insert(map.Offset + shift, map.NewString);
    shift += map.NewString.Length - map.Length;
}
string result = sb.ToString();

OrderBy确保替换从左到右执行。如果您知道按此顺序提供了映射,则可以删除OrderBy

另一种更简单的方法是从右端的替换开始并向后工作,这样角色转换不会改变尚未执行的替换的位置:

var sb = new StringBuilder("dog says gav");
foreach (MapItem map in maps.OrderByDescending(m => m.Offset)) {
    sb.Remove(map.Offset, map.Length);
    sb.Insert(map.Offset, map.NewString);
}
string result = sb.ToString();

如果映射已按升序排序,则简单的反向for语句似乎是合适的:

var sb = new StringBuilder("dog says gav");
for (int i = maps.Count - 1; i >= 0; i--) {
    MapItem map = maps[i];
    sb.Remove(map.Offset, map.Length);
    sb.Insert(map.Offset, map.NewString);
}
string result = sb.ToString();

答案 1 :(得分:0)

您可以在下面写一个Extension Method

public static class ExtensionMethod
{
    public static string ReplaceSubstringByMap(this string str, List<mapItem> map)
    {
        int offsetShift = 0;

        foreach (mapItem mapItem in map.OrderBy(x => x.offset))
        {
            str = str.Remove(mapItem.offset + offsetShift, mapItem.length).Insert(mapItem.offset + offsetShift, mapItem.newString);
            offsetShift += mapItem.newString.Length - mapItem.length;
        }
        return str;
    }
}

并调用它如下:

var map = new List<mapItem>
              {
                  new mapItem
                      {
                          offset = 0,
                          length = 1,
                          newString = "frog"
                      },
                  new mapItem
                      {
                          offset = 9,
                          length = 1,
                          newString = "kva"
                      }
              };
string str = "dog says gav";
var result = str.ReplaceSubstringByMap(map);