在字符串中一次搜索多个guid的最佳方法?

时间:2012-11-19 20:17:36

标签: c# search guid trie

我面前有一个在字符串中搜索90,000个GUID的问题。我需要获取每个GUID的所有实例。从技术上讲,我也需要更换它们,但这是另一个故事。

目前,我正在使用正则表达式单独搜索每一个。但是我想到通过一起搜索它们可以获得更好的性能。我已经阅读了过去的尝试并且从未使用过,但我想到我可以构建所有90,000个GUID并使用它来搜索。

或者,也许.NET中存在可以执行此操作的现有库。我突然想到,没有理由说我只能用一个巨大的正则表达式来获得良好的性能,但这似乎不起作用。

除此之外,也许我可以使用一些与GUID结构相关的聪明技巧来获得更好的结果。

这对我来说并不是一个至关重要的问题,但我想我可能会学到一些东西。

4 个答案:

答案 0 :(得分:1)

我开发了一种替代大量字符串的方法,这可能很有用:

A better way to replace many strings - obfuscation in C#

另一种选择是使用正则表达式查找字符串中的所有GUID,然后遍历它们并检查每个GUID是否是GUID集的一部分。

基本示例,使用Dictionary快速查找GUID:

Dictionary<string, string> guids = new Dictionary<string, string>();
guids.Add("3f74a071-54fc-10de-0476-a6b991f0be76", "(replacement)");

string text = "asdf 3f74a071-54fc-10de-0476-a6b991f0be76 lkaq2hlqwer";

text = Regex.Replace(text, @"[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}", m => {
  string replacement;
  if (guids.TryGetValue(m.Value, out replacement)) {
    return replacement;
  } else {
    return m.Value;
  }
});

Console.WriteLine(text);

输出:

asdf (replacement) lkaq2hlqwer

答案 1 :(得分:1)

使用RegEx无法获得良好的性能,因为它的性能本质上很差。此外,如果所有GUID共享相同的格式,您只需要一个RegEx。并且regex.Replace(input, replacement);会这样做。

如果你已经在内存中有guid列表,那么循环遍历该列表并像这样调用String.Replace

会更好
 foreach(string guid in guids)
     inputString.replace(guid, replacement);

答案 2 :(得分:1)

看看Rabin-Karp字符串搜索算法。它非常适合在字符串中进行多模式搜索:

http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_string_search_algorithm#Rabin.E2.80.93Karp_and_multiple_pattern_search

答案 3 :(得分:0)

好的,这看起来不错。所以这里要清楚的是原始代码,在示例字符串上运行了65秒:

   var unusedGuids = new HashSet<Guid>(oldToNewGuid.Keys);

    foreach (var guid in oldToNewGuid) {
        var regex = guid.Key.ToString();

        if (!Regex.IsMatch(xml, regex))
             unusedGuids.Add(guid.Key);
        else
            xml = Regex.Replace(xml, regex, guid.Value.ToString());
    }

新代码如下,需要6.7秒:

var unusedGuids = new HashSet<Guid>(oldToNewGuid.Keys);

var guidHashes = new MultiValueDictionary<int, Guid>();

foreach (var guid in oldToNewGuid.Keys) {
    guidHashes.Add(guid.ToString().GetHashCode(), guid);
}

var indices = new List<Tuple<int, Guid>>();

const int guidLength = 36;

for (int i = 0; i < xml.Length - guidLength; i++) {
    var substring = xml.Substring(i, guidLength);

    foreach (var value in guidHashes.GetValues(substring.GetHashCode())) {
         if (value.ToString() == substring) {
        unusedGuids.Remove(value);
        indices.Add(new Tuple<int, Guid>(i, value));
        break;
         }
    }
}

var builder = new StringBuilder();

int start = 0;
for (int i = 0; i < indices.Count; i++) {
    var tuple = indices[i];
    var substring = xml.Substring(start, tuple.Item1 - start);
    builder.Append(substring);
    builder.Append(oldToNewGuid[tuple.Item2].ToString());
    start = tuple.Item1 + guidLength;
}

builder.Append(xml.Substring(start, xml.Length - start));

xml = builder.ToString();