C# 将字符串拆分为标记的更直观方法?

C# More intuitive way to split a string into tokens?

我有一个接受字符串的方法,其中包含各种字符,但我只关心下划线“_”和美元符号“$”。我想通过下划线将字符串拆分为标记,因为每一部分 b/w 下划线都包含重要信息。

但是,如果 $ 包含在下划线之间的区域中,则应从下划线的最后一次出现到末尾创建一个标记(忽略最后一部分中的任何下划线)。

例子

输入:Hello_To_The$Great_World

预期标记:你好,To,The$Great_World

问题

我在下面有一个解决方案,但我想知道是否有 cleaner/more 比我下面的方法更直观的方法?

var aTokens = new List<string>();
var aPos = 0;
for (var aNum = 0; aNum < item.Length; aNum++)
{
    if (aNum == item.Length - 1)
    {
        aTokens.Add(item.Substring(aPos, item.Length - aPos));
        break;
    }               
    if (item[aNum] == '$')
    {
        aTokens.Add(item.Substring(aPos, item.Length - aPos));
        break;
    }
    if (item[aNum] == '_')
    {
    aTokens.Add(item.Substring(aPos, aNum - aPos));
    aPos = aNum + 1;
    }
}

此方法既不高效也不干净,但它可以让您大致了解如何执行此操作:

  1. 将字符串拆分为标记
  2. 查找包含$
  3. 的第一个字符串的索引
  4. Return 一个包含前 n 个标记的新数组,最后一个标记是剩余字符串的连接。

利用 IEnumerable 或通过 for 循环而不是所有这些 Array.Copy 东西来做事可能更有用......但你明白了它的要点。

private string[] SomeMethod(string arg)
{
    var strings = arg.Split(new[] { '_' });

    var indexedValue = strings.Select((v, i) => new { Value = v, Index = i }).FirstOrDefault(x => x.Value.Contains("$"));

    if (indexedValue != null)
    {
        var count = indexedValue.Index + 1;

        string[] final = new string[count];
        Array.Copy(strings, 0, final, 0, indexedValue.Index);
        final[indexedValue.Index] = String.Join("_", strings, indexedValue.Index, strings.Length - indexedValue.Index);
        return final;
    }

    return strings;
}

这是我的版本(循环是 所以 去年...)

const char dollar = '$';
const char underscore = '_';

var item = "Hello_To_The$Great_World";
var aTokens = new List<string>();

int dollarIndex = item.IndexOf(dollar);
if (dollarIndex >= 0)
{
    int lastUnderscoreIndex = item.LastIndexOf(underscore, dollarIndex);
    if (lastUnderscoreIndex >= 0)
    {
        aTokens.AddRange(item.Substring(0, lastUnderscoreIndex).Split(underscore));
        aTokens.Add(item.Substring(lastUnderscoreIndex + 1));
    }
    else
    {
        aTokens.Add(item);
    }
}
else
{
    aTokens.AddRange(item.Split(underscore));
}

编辑:

我应该补充一点,cleaner/more 直觉是非常主观的,正如您从提供的各种答案中发现的那样。从可维护性的角度来看,对您编写的用于解析的方法进行单元测试更为重要!

测试此处发布的各种方法的性能也是一个有趣的练习 - 很快就会发现您的原始版本比使用正则表达式快得多! (尽管在现实生活中,此方法的性能不太可能对您的应用程序产生任何影响!)

您可以通过 _ 之前没有 $ 来拆分字符串。

为此,您可以使用以下正则表达式:

(?<!$.*)_

示例代码:

string input = "Hello_To_The$Great_World";
string[] output = Regex.Split(input, @"(?<!$.*)_");

您也可以在没有正则表达式和循环的情况下完成任务,但需要 2 个拆分的帮助:

string input = "Hello_To_The$Great_World";
string[] temp = input.Split(new[] { '$' }, 2);
string[] output = temp[0].Split('_');
if (temp.Length > 1)
    output[output.Length - 1] = output[output.Length - 1] + "$" + temp[1];