我正在编写一个应用程序,该应用程序旨在以以下格式处理数千篇包含大量spintax的文章/条目:
{Hello|Hi} {World|There!}, how are you?
但是,当我使用profiler运行应用程序时,我注意到处理regex的部分占用了大量资源,我的应用程序最终由于内存不足而崩溃。有谁能建议一种改进我的代码或者更好的解析spintax的方法吗?
public static String Spin(String text)
{
Regex reg = new Regex(@"\{[^\{\}]*\}");
Random rand = new Random((int)DateTime.Now.Ticks);
while (true)
{
Match m = reg.Match(text);
if (!m.Success) break;
String[] parts = m.Value.TrimStart('{').TrimEnd('}').Split('|');
int i = rand.Next(parts.Length);
text = text.Substring(0, m.Index) + parts[i] + text.Substring(m.Index + m.Length);
}
return text;
}
最佳答案
我已经实现了我的快速版本(noRegex
、noSplit
、noSubstring
、noReplace
和其他字符串操作方法)。要复制字符串,我正在使用String.CopyTo
将符号复制到一个普通的char
数组。
此代码完全支持嵌套的spintax(可能无限深度)。一个限制是每个税的最大选择数,目前是100,但可以改为1000个或更多。另一个限制是输入字符串的最大长度,现在是100000,但也可以增加。
关于性能-我的测试表明,这段代码比任何优化的regex解决方案(包括jim mischel的解决方案)快15倍,比使用子字符串和其他字符串操作方法的版本快5倍。我已经在VS2012的发布模式下用优化代码设置测试过了。
static int[] partIndices = new int[100];
static int[] depth = new int[100];
static char[] symbolsOfTextProcessed = new char[100000];
public static String SpinEvenMoreFaster(String text)
{
int cur = SpinEvenMoreFasterInner(text, 0, text.Length, 0);
return new String(symbolsOfTextProcessed, 0, cur);
}
public static int SpinEvenMoreFasterInner(String text, int start, int end, int symbolIndex)
{
int last = start;
for (int i = start; i < end; i++)
{
if (text[i] == '{')
{
int k = 1;
int j = i + 1;
int index = 0;
partIndices[0] = i;
depth[0] = 1;
for (; j < end && k > 0; j++)
{
if (text[j] == '{')
k++;
else if (text[j] == '}')
k--;
else if (text[j] == '|')
{
if (k == 1)
{
partIndices[++index] = j;
depth[index] = 1;
}
else
depth[index] = k;
}
}
if (k == 0)
{
partIndices[++index] = j - 1;
int part = rand.Next(index);
text.CopyTo(last, symbolsOfTextProcessed, symbolIndex, i - last);
symbolIndex += i - last;
if (depth[part] == 1)
{
text.CopyTo(partIndices[part] + 1, symbolsOfTextProcessed, symbolIndex, partIndices[part + 1] - partIndices[part] - 1);
symbolIndex += partIndices[part + 1] - partIndices[part] - 1;
}
else
{
symbolIndex = SpinEvenMoreFasterInner(text, partIndices[part] + 1, partIndices[part + 1], symbolIndex);
}
i = j - 1;
last = j;
}
}
}
text.CopyTo(last, symbolsOfTextProcessed, symbolIndex, end - last);
return symbolIndex + end - last;
}