【问题标题】:C# String Search with multiple substrings具有多个子字符串的 C# 字符串搜索
【发布时间】:2018-11-16 18:41:36
【问题描述】:

所以我正在研究资源列表的过滤器,其中一个过滤器是名称属性(字符串)。

作为一个(愚蠢的)示例:资源名称为“Big,Red/Square Table”,过滤器为“Table Red”,它应该是有效资源

这是我可以利用我仅有的一点时间想出的:

static void ApplyNameFilter(ref ApplicationViewModel model, string filter)
{
    if (string.IsNullOrEmpty(filter) || filter == "") return;
    char[] separators = {' ', ',', '.', '/', '\\', '|', '_', '-'};
    var validResources = new List<ResourceModel>();

    foreach (var resource in model.ResourcesViewModel.Resources)
    {
        var filterSubstrings =
            filter
            .ToLower()
            .Split(separators)
            .ToList();

        var resourceSubstrings =
            resource.Name
            .ToLower()
            .Split(separators)
            .ToList();

        resourceSubstrings.ForEach(substring => {
            if (filterSubstrings.Contains(substring))
                filterSubstrings.RemoveAll(sub => sub == substring);
        });

        if (filterSubstrings.Count == 0)
            validResources.Add(resource);
    }

    model.ResourcesViewModel.Resources = validResources;
}

我应该为此采取不同的方法吗?

编辑: 结束了这个,直到我弄清楚 RegEx

static void ApplyNameFilter(ref ApplicationViewModel model, string filter)
{
    if (string.IsNullOrEmpty(filter)) return;

    char[] separators = {' ', ',', '.', '/', '\\', '|', '_', '-'};
    var filterSubstrings =
        filter
            .ToLower()
            .Split(separators)
            .ToList();

    var validResources = model.ResourcesViewModel.Resources
        .Where(resource => filterSubstrings.All(fs => resource.Name.ToLower().Contains(fs)))
        .ToList();

    model.ResourcesViewModel.Resources = validResources;
}    

【问题讨论】:

  • 是的。绝对看向regex 解决方案 - 你肯定会有更简洁的代码。还有其他方法可以给这只猫剥皮,但你必须回到你的 comp sci 101 过去并考虑动态编程(至少这是我想到的,哈哈)。基于单一责任原则的方法也可能使您的生活变得不那么地狱。在regex 和非正则表达式方法中,尝试利用基于不变性的方法。你会很感激你以后没有就地改变事情。
  • 虽然我没有使用过多的 RegEx,但我知道它非常强大。有没有办法根据输入生成正确的正则表达式模式?
  • @Xeyth,添加 code4life 优秀评论。我还将澄清,关于具体点,如果您正在使用的方法只需要资源列表,您不想让该方法“知道”您的所有对象及其层次结构。一些原因是:以防层次结构发生变化,或者您希望在应用程序的其他部分中使用此逻辑。你不需要传递方法不关心的东西,也不应该传递。
  • @Xeyth:绝对。如果您使用的是 .NET 4.5 或更高版本,由于您可以利用字符串插值,它会变得更加容易。例如,$"{your variable here}regex expression here" - 这只是一个非常原始的、即兴的例子。我强烈建议使用谷歌搜索正则表达式,您不需要非常复杂的正则表达式来完成您正在尝试做的事情。
  • @Xeyth,如果您只想“美化”您的方法,您可以使用.Intersect.All,它们是不可变的,并且几乎可以为您提供解决方案。例如:filterSubstrings.Intersect(resourceSubstrings).Count() == filterSubstrings.CountfilterSubstrings.All(fs =&gt; resourceSubstrings.Contains(fs))。此外,您不需要在每次迭代中计算 filterSubstring,它们不会改变。所以把它们排除在你的循环之外。

标签: c# string search


【解决方案1】:

您可以使用 LINQ 使其更简洁(并且可能更快,因为您正在创建 Lists 并不必要地删除每个资源上的元素,尽管非 LINQ 解决方案可能更快)。

var validResources = model.ResourcesViewModel.Resources
                        .Where(resource => {
                            var resourceSubstrings = resource.Name.ToLower().Split(separators).ToHashSet();
                            return filterSubstrings.All(fs => resourceSubstrings.Contains(fs));
                        })
                        .ToList();

如果您愿意接受Name 内的所有过滤器子字符串,而不管separators,那么您可以简化为:

var validResources = model.ResourcesViewModel.Resources
                        .Where(resource => filterSubstrings.All(fs => resource.Name.ToLower().Contains(fs)))
                        .ToList();

【讨论】:

    猜你喜欢
    • 2012-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 1970-01-01
    • 2020-06-25
    • 1970-01-01
    相关资源
    最近更新 更多