gpt4 book ai didi

c# - 是否有人围绕 StringBuilders 或 Streams 实现了 Regex 和/或 Xml 解析器?

转载 作者:可可西里 更新时间:2023-11-01 09:15:05 24 4
gpt4 key购买 nike

我正在构建一个压力测试客户端,它使用客户端可以召集的尽可能多的线程来攻击服务器并分析响应。我经常发现自己受到垃圾收集(和/或缺乏垃圾收集)的限制,在大多数情况下,它归结为我实例化的字符串,只是为了将它们传递给 Regex 或 Xml 解析例程。

如果反编译 Regex 类,您会看到在内部,它使用 StringBuilder 来做几乎所有事情,但您不能传递给它一个字符串生成器;它有助于在开始使用之前深入研究私有(private)方法,因此扩展方法也不会解决它。如果您想从 System.Xml.Linq 中的解析器中获取对象图,您会遇到类似的情况。

这不是迂腐的提前过度优化的情况。我看过 Regex replacements inside a StringBuilder问题和其他。我还分析了我的应用程序以查看上限来自何处,并且现在使用 Regex.Replace() 确实在方法链中引入了显着的开销,我正在尝试使用每小时数百万个请求,并检查 XML 响应中的错误和嵌入式诊断代码。我已经摆脱了几乎所有其他限制吞吐量的低效率问题,而且我什至通过扩展 StringBuilder 来在不需要捕获组或反向引用时执行通配符查找/替换,从而减少了很多 Regex 开销,但在我看来,现在有人已经完成了基于 Regex 和 Xml 解析实用程序的自定义 StringBuilder(或者更好的是 Stream)。

好吧,说完了,但我必须自己做吗?

更新:我找到了一个解决方法,可以将峰值内存消耗从几千兆字节降低到几百兆字节,所以我将其发布在下面。我没有将其添加为答案,因为 a) 我通常讨厌这样做,并且 b) 我仍然想知道是否有人在我之前花时间自定义 StringBuilder 来执行正则表达式(或反之亦然)。

在我的例子中,我无法使用 XmlReader,因为我正在摄取的流在某些元素中包含一些无效的二进制内容。为了解析 XML,我必须清空这些元素。我以前使用单个静态编译的 Regex 实例来进行替换,这会消耗大量内存(我正在尝试处理 ~300 10KB 文档/秒)。大幅减少消耗的变化是:

  1. 我添加了这个 StringBuilder Extensions article onCodeProject 中的代码对于方便的 IndexOf 方法。
  2. 我添加了一个(非常)粗糙的WildcardReplace 方法,每次调用允许一个 通配符(* 或?)
  3. 我用 WildcardReplace() 调用替换了 Regex 用法,以清空违规元素的内容

这是非常不漂亮的,并且仅在我自己的目的需要的范围内进行了测试;我本来可以让它更优雅、更强大,但是 YAGNI 之类的,我很着急。这是代码:

/// <summary>
/// Performs basic wildcard find and replace on a string builder, observing one of two
/// wildcard characters: * matches any number of characters, or ? matches a single character.
/// Operates on only one wildcard per invocation; 2 or more wildcards in <paramref name="find"/>
/// will cause an exception.
/// All characters in <paramref name="replaceWith"/> are treated as literal parts of
/// the replacement text.
/// </summary>
/// <param name="find"></param>
/// <param name="replaceWith"></param>
/// <returns></returns>
public static StringBuilder WildcardReplace(this StringBuilder sb, string find, string replaceWith) {
if (find.Split(new char[] { '*' }).Length > 2 || find.Split(new char[] { '?' }).Length > 2 || (find.Contains("*") && find.Contains("?"))) {
throw new ArgumentException("Only one wildcard is supported, but more than one was supplied.", "find");
}
// are we matching one character, or any number?
bool matchOneCharacter = find.Contains("?");
string[] parts = matchOneCharacter ?
find.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)
: find.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries);
int startItemIdx;
int endItemIdx;
int newStartIdx = 0;
int length;
while ((startItemIdx = sb.IndexOf(parts[0], newStartIdx)) > 0
&& (endItemIdx = sb.IndexOf(parts[1], startItemIdx + parts[0].Length)) > 0) {
length = (endItemIdx + parts[1].Length) - startItemIdx;
newStartIdx = startItemIdx + replaceWith.Length;
// With "?" wildcard, find parameter length should equal the length of its match:
if (matchOneCharacter && length > find.Length)
break;
sb.Remove(startItemIdx, length);
sb.Insert(startItemIdx, replaceWith);
}
return sb;
}

最佳答案

在这里试试这个。一切都是基于字符的,效率级别相对较低。可以使用任意数量的 *?。但是,您的 * 现在是 而您的 ? 现在是 。大约三天的工作进行了这项工作,以使其尽可能干净。您甚至可以一次输入多个查询!

示例用法:wildcard(new StringBuilder("Hello and welcome"), "hello✪w★l", "be") 结果为“become”。

////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////// Search for a string/s inside 'text' using the 'find' parameter, and replace with a string/s using the replace parameter
// ✪ represents multiple wildcard characters (non-greedy)
// ★ represents a single wildcard character
public StringBuilder wildcard(StringBuilder text, string find, string replace, bool caseSensitive = false)
{
return wildcard(text, new string[] { find }, new string[] { replace }, caseSensitive);
}
public StringBuilder wildcard(StringBuilder text, string[] find, string[] replace, bool caseSensitive = false)
{
if (text.Length == 0) return text; // Degenerate case

StringBuilder sb = new StringBuilder(); // The new adjusted string with replacements
for (int i = 0; i < text.Length; i++) { // Go through every letter of the original large text

bool foundMatch = false; // Assume match hasn't been found to begin with
for(int q=0; q< find.Length; q++) { // Go through each query in turn
if (find[q].Length == 0) continue; // Ignore empty queries

int f = 0; int g = 0; // Query cursor and text cursor
bool multiWild = false; // multiWild is ✪ symbol which represents many wildcard characters
int multiWildPosition = 0;

while(true) { // Loop through query characters
if (f >= find[q].Length || (i + g) >= text.Length) break; // Bounds checking
char cf = find[q][f]; // Character in the query (f is the offset)
char cg = text[i + g]; // Character in the text (g is the offset)
if (!caseSensitive) cg = char.ToLowerInvariant(cg);
if (cf != '★' && cf != '✪' && cg != cf && !multiWild) break; // Break search, and thus no match is found
if (cf == '✪') { multiWild = true; multiWildPosition = f; f++; continue; } // Multi-char wildcard activated. Move query cursor, and reloop
if (multiWild && cg != cf && cf != '★') { f = multiWildPosition + 1; g++; continue; } // Match since MultiWild has failed, so return query cursor to MultiWild position
f++; g++; // Reaching here means that a single character was matched, so move both query and text cursor along one
}

if (f == find[q].Length) { // If true, query cursor has reached the end of the query, so a match has been found!!!
sb.Append(replace[q]); // Append replacement
foundMatch = true;
if (find[q][f - 1] == '✪') { i = text.Length; break; } // If the MultiWild is the last char in the query, then the rest of the string is a match, and so close off
i += g - 1; // Move text cursor along by the amount equivalent to its found match
}
}
if (!foundMatch) sb.Append(text[i]); // If a match wasn't found at that point in the text, then just append the original character
}
return sb;
}

关于c# - 是否有人围绕 StringBuilders 或 Streams 实现了 Regex 和/或 Xml 解析器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11533110/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com