gpt4 book ai didi

c# - 如何使用 .NET 按字符串拆分字符串并包含分隔符?

转载 作者:行者123 更新时间:2023-12-02 18:34:49 27 4
gpt4 key购买 nike

有很多类似的问题,但显然没有完美匹配,这就是我问的原因。

我想通过字符串分隔符列表(例如 xxyy)拆分随机字符串(例如 123xx456yy789),并且在结果中包含分隔符(此处:123xx456yy789)。

良好的表现是一个不错的奖励。如果可能的话,应避免使用正则表达式。

更新:我做了一些性能检查并比较了结果(虽然懒得正式检查它们)。测试的解决方案是(随机顺序):

  1. Gabe
  2. Guffa
  3. Mafu
  4. Regex

其他解决方案未进行测试,因为它们要么与另一个解决方案类似,要么出现得太晚。

这是测试代码:

class Program
{
private static readonly List<Func<string, List<string>, List<string>>> Functions;
private static readonly List<string> Sources;
private static readonly List<List<string>> Delimiters;

static Program ()
{
Functions = new List<Func<string, List<string>, List<string>>> ();
Functions.Add ((s, l) => s.SplitIncludeDelimiters_Gabe (l).ToList ());
Functions.Add ((s, l) => s.SplitIncludeDelimiters_Guffa (l).ToList ());
Functions.Add ((s, l) => s.SplitIncludeDelimiters_Naive (l).ToList ());
Functions.Add ((s, l) => s.SplitIncludeDelimiters_Regex (l).ToList ());

Sources = new List<string> ();
Sources.Add ("");
Sources.Add (Guid.NewGuid ().ToString ());

string str = "";
for (int outer = 0; outer < 10; outer++) {
for (int i = 0; i < 10; i++) {
str += i + "**" + DateTime.UtcNow.Ticks;
}
str += "-";
}
Sources.Add (str);

Delimiters = new List<List<string>> ();
Delimiters.Add (new List<string> () { });
Delimiters.Add (new List<string> () { "-" });
Delimiters.Add (new List<string> () { "**" });
Delimiters.Add (new List<string> () { "-", "**" });
}

private class Result
{
public readonly int FuncID;
public readonly int SrcID;
public readonly int DelimID;
public readonly long Milliseconds;
public readonly List<string> Output;

public Result (int funcID, int srcID, int delimID, long milliseconds, List<string> output)
{
FuncID = funcID;
SrcID = srcID;
DelimID = delimID;
Milliseconds = milliseconds;
Output = output;
}

public void Print ()
{
Console.WriteLine ("S " + SrcID + "\tD " + DelimID + "\tF " + FuncID + "\t" + Milliseconds + "ms");
Console.WriteLine (Output.Count + "\t" + string.Join (" ", Output.Take (10).Select (x => x.Length < 15 ? x : x.Substring (0, 15) + "...").ToArray ()));
}
}

static void Main (string[] args)
{
var results = new List<Result> ();

for (int srcID = 0; srcID < 3; srcID++) {
for (int delimID = 0; delimID < 4; delimID++) {
for (int funcId = 3; funcId >= 0; funcId--) { // i tried various orders in my tests
Stopwatch sw = new Stopwatch ();
sw.Start ();

var func = Functions[funcId];
var src = Sources[srcID];
var del = Delimiters[delimID];

for (int i = 0; i < 10000; i++) {
func (src, del);
}
var list = func (src, del);
sw.Stop ();

var res = new Result (funcId, srcID, delimID, sw.ElapsedMilliseconds, list);
results.Add (res);
res.Print ();
}
}
}
}
}

正如您所看到的,这实际上只是一个快速而肮脏的测试,但我以不同的顺序多次运行测试,结果总是非常一致。对于较大的数据集,测量的时间范围在毫秒到秒的范围内。在接下来的评估中,我忽略了低毫秒范围内的值,因为它们在实践中似乎可以忽略不计。这是我的盒子上的输出:

S 0     D 0     F 3     11ms1S 0     D 0     F 2     7ms1S 0     D 0     F 1     6ms1S 0     D 0     F 0     4ms0S 0     D 1     F 3     28ms1S 0     D 1     F 2     8ms1S 0     D 1     F 1     7ms1S 0     D 1     F 0     3ms0S 0     D 2     F 3     30ms1S 0     D 2     F 2     8ms1S 0     D 2     F 1     6ms1S 0     D 2     F 0     3ms0S 0     D 3     F 3     30ms1S 0     D 3     F 2     10ms1S 0     D 3     F 1     8ms1S 0     D 3     F 0     3ms0S 1     D 0     F 3     9ms1       9e5282ec-e2a2-4...S 1     D 0     F 2     6ms1       9e5282ec-e2a2-4...S 1     D 0     F 1     5ms1       9e5282ec-e2a2-4...S 1     D 0     F 0     5ms1       9e5282ec-e2a2-4...S 1     D 1     F 3     63ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 1     F 2     37ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 1     F 1     29ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 1     F 0     22ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 2     F 3     30ms1       9e5282ec-e2a2-4...S 1     D 2     F 2     10ms1       9e5282ec-e2a2-4...S 1     D 2     F 1     10ms1       9e5282ec-e2a2-4...S 1     D 2     F 0     12ms1       9e5282ec-e2a2-4...S 1     D 3     F 3     73ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 3     F 2     40ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 3     F 1     33ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 1     D 3     F 0     30ms9       9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37S 2     D 0     F 3     10ms1       0**634226552821...S 2     D 0     F 2     109ms1       0**634226552821...S 2     D 0     F 1     5ms1       0**634226552821...S 2     D 0     F 0     127ms1       0**634226552821...S 2     D 1     F 3     184ms21      0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... -S 2     D 1     F 2     364ms21      0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... -S 2     D 1     F 1     134ms21      0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... -S 2     D 1     F 0     517ms20      0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226552821... -S 2     D 2     F 3     688ms201     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 2     F 2     2404ms201     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 2     F 1     874ms201     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 2     F 0     717ms201     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 3     F 3     1205ms221     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 3     F 2     3471ms221     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 3     F 1     1008ms221     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **S 2     D 3     F 0     1095ms220     0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 634226552821217... **

我比较了结果,这就是我的发现:

  • 所有 4 个功能都足够快,适合日常使用。
  • 原生版本(也就是我最初编写的版本)在计算时间方面是最差的。
  • 正则表达式在小型数据集上有点慢(可能是由于初始化开销)。
  • 正则表达式在大数据方面表现出色,并且速度与非正则表达式解决方案相似。
  • 总体而言,性能方面最好的似乎是 Guffa 的版本,这也是代码所期望的。
  • Gabe 的版本有时会省略某个项目,但我没有对此进行调查(错误?)。

为了结束这个主题,我建议使用 Regex,它相当快。如果性能很关键,我更喜欢 Guffa 的实现。

最佳答案

尽管您不愿意使用正则表达式,但它实际上通过使用组和 Regex.Split 方法很好地保留了分隔符:

string input = "123xx456yy789";
string pattern = "(xx|yy)";
string[] result = Regex.Split(input, pattern);

如果仅使用 "xx|yy" 从模式中删除括号,则不会保留分隔符。如果您使用任何在正则表达式中具有特殊含义的元字符,请务必在模式上使用 Regex.Escape。字符包括\、*、+、?、|、{、[、(、)、^、$、.、#。例如,分隔符 . 应转义 \.。给定一个分隔符列表,您需要使用管道 | 符号对它们进行“或”,这也是一个被转义的字符。要正确构建模式,请使用以下代码(感谢 @gabe 指出这一点):

var delimiters = new List<string> { ".", "xx", "yy" };
string pattern = "(" + String.Join("|", delimiters.Select(d => Regex.Escape(d))
.ToArray())
+ ")";

括号是连接在一起的,而不是包含在模式中,因为它们会根据您的目的被错误地转义。

编辑:此外,如果delimiters列表恰好为空,最终模式将错误地为(),这会导致空白匹配。为了防止这种情况,可以使用分隔符检查。考虑到所有这些,代码片段变为:

string input = "123xx456yy789";
// to reach the else branch set delimiters to new List();
var delimiters = new List<string> { ".", "xx", "yy", "()" };
if (delimiters.Count > 0)
{
string pattern = "("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d))
.ToArray())
+ ")";
string[] result = Regex.Split(input, pattern);
foreach (string s in result)
{
Console.WriteLine(s);
}
}
else
{
// nothing to split
Console.WriteLine(input);
}

如果您需要对分隔符进行不区分大小写的匹配,请使用 RegexOptions.IgnoreCase 选项:Regex.Split(input, pattern, RegexOptions.IgnoreCase)

编辑#2:到目前为止,解决方案匹配可能是较大字符串的子字符串的分割标记。如果分割标记需要完全匹配,而不是子字符串的一部分,例如句子中的单词用作分隔符的场景,则应在周围添加单词边界 \b 元字符模式。

例如,考虑这句话(是的,这很老套):“欢迎来到 stackoverflow...堆栈永远不会溢出!”

如果分隔符是 { "stack", "flow"} 当前解决方案将拆分 "stackoverflow"并返回 3 个字符串 { "stack", "over", "flow"}。如果您需要完全匹配,那么唯一会分割的位置是句子后面的“stack”一词,而不是“stackoverflow”。

要实现精确匹配行为,请更改模式以包含 \b,如 \b(delim1|delim2|delimN)\b:

string pattern = @"\b("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d)))
+ @")\b";

最后,如果需要修剪分隔符前后的空格,请在模式周围添加 \s*,如 \s*(delim1|delim2|delimN)\s*。这可以与 \b 组合,如下所示:

string pattern = @"\s*\b("
+ String.Join("|", delimiters.Select(d => Regex.Escape(d)))
+ @")\b\s*";

关于c# - 如何使用 .NET 按字符串拆分字符串并包含分隔符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2484919/

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