【问题标题】:C# matching two text files, case sensitive issueC#匹配两个文本文件,区分大小写的问题
【发布时间】:2011-02-13 11:41:01
【问题描述】:

我有两个文件,sourcecolumns.txtdestcolumns.txt。我需要做的是将 source 与 dest 进行比较,如果 dest 不包含源值,则将其写入新文件。下面的代码有效,除了我有这样的区分大小写的问题:

来源:CPI
目标:CPI

由于大写字母,这些不匹配,所以我得到不正确的输出。任何帮助总是受欢迎的!

string[] sourcelinestotal =
    File.ReadAllLines("C:\\testdirectory\\" + "sourcecolumns.txt");
string[] destlinestotal =
    File.ReadAllLines("C:\\testdirectory\\" + "destcolumns.txt");

foreach (string sline in sourcelinestotal)
{
    if (destlinestotal.Contains(sline))
    {
    }
    else
    {
        File.AppendAllText("C:\\testdirectory\\" + "missingcolumns.txt", sline);
    }
}

【问题讨论】:

    标签: c# string case-insensitive string-comparison


    【解决方案1】:

    您可以使用IEnumerable<string> 的扩展方法来做到这一点,例如:

    public static class EnumerableExtensions
    {
        public static bool Contains( this IEnumerable<string> source, string value, StringComparison comparison )
        {
             if (source == null)
             {
                 return false; // nothing is a member of the empty set
             }
             return source.Any( s => string.Equals( s, value, comparison ) );
        }
    }
    

    然后改变

    if (destlinestotal.Contains( sline ))
    

    if (destlinestotal.Contains( sline, StringComparison.OrdinalIgnoreCase ))
    

    但是,如果集合很大并且/或者您要经常这样做,那么您的处理方式就会非常低效。本质上,您正在执行 O(n2) 操作 - 对于源中的每一行,您可能会将其与目标中的所有行进行比较。最好使用不区分大小写的比较器从目标列创建一个 HashSet,然后遍历源列,检查每个列是否存在于目标列的 HashSet 中。这将是一个 O(n) 算法。请注意,HashSet 上的 Contains 将使用您在构造函数中提供的比较器。

    string[] sourcelinestotal = 
        File.ReadAllLines("C:\\testdirectory\\" + "sourcecolumns.txt"); 
    HashSet<string> destlinestotal = 
                    new HashSet<string>(
                      File.ReadAllLines("C:\\testdirectory\\" + "destcolumns.txt"),
                      StringComparer.OrdinalIgnoreCase
                    );
    
    foreach (string sline in sourcelinestotal) 
    { 
        if (!destlinestotal.Contains(sline)) 
        { 
            File.AppendAllText("C:\\testdirectory\\" + "missingcolumns.txt", sline); 
        } 
    }
    

    回想起来,我实际上更喜欢这个解决方案,而不是简单地为 IEnumerable&lt;string&gt; 编写自己的不区分大小写的包含,除非你需要其他方法。通过使用 HashSet 实现,实际上需要维护的(您自己的)代码更少。

    【讨论】:

    • @aba - 在一般情况下,集合可能包含空字符串,但在这种情况下可能不包含。
    • 我无法编译使用泛型类型 'System.Collections.Generic.HashSet' 需要 '1' 类型参数 C
    • 我在 HashSet 构造函数中省略了类型说明符。我已经解决了这个问题。
    • @tvanfosson - 是否有理由不只做两个包含行的 IEnumerables 并使用 List1.Except(List2, StringComparison.OrdinalIgnoreCase)。我会认为这会以最有效的方式实施?
    • @Martin 如果第二个集合是一个列表,则基于 Except 的解决方案可能是 O(N log N)(或 O(N^2)),而基于 HashSet 的解决方案是 O(N)。差异的原因是您要么对两个列表进行排序,因此您可以进行 O(N) 比较(或对第一个中的每个项目的第二个列表进行 O(N) 遍历)。使用 HashSet,您可以对第一组中的每个项目进行 O(1) 查找。
    【解决方案2】:

    为您的包含使用扩展方法。找到了一个很好的例子here on stack overflow 代码不是我的,但我会在下面发布。

    public static bool Contains(this string source, string toCheck, StringComparison comp) 
    {
        return source.IndexOf(toCheck, comp) >= 0;
    }
    
    string title = "STRING";
    bool contains = title.Contains("string", StringComparison.OrdinalIgnoreCase);
    

    【讨论】:

    • 这并不能解决问题——他想查看字符串的collection是否包含不区分大小写的特定字符串。这仅以不区分大小写的方式检查 string 是否包含另一个字符串。您需要在 IEnumerable&lt;string&gt; 上使用扩展方法,而不是 string
    • 我看到了你的回答,比我的好多了。老实说,我没有考虑性能方面,而且我不知道 HashSet 的重载构造函数。无论哪种情况,这总是一个不错的扩展!
    【解决方案3】:

    如果您不需要区分大小写,请在比较之前使用string.ToUpper 将您的行转换为大写。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-30
    • 2013-02-19
    • 2022-06-13
    • 2020-12-23
    • 2016-11-05
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    相关资源
    最近更新 更多