代码之家  ›  专栏  ›  技术社区  ›  Rusty Nail

字符串的快捷方式。除了like List。除了

  •  0
  • Rusty Nail  · 技术社区  · 7 年前

    像新的.NET 6、7等等,我们有一个列表除外的类。

    List<int> A = new List<int>();
    List<int> B = new List<int>();
    List<int> C = A.Except(B).ToList();
    

    string A = "<div><p>One</p><p>Two</p></div>";
    string B = "<div><p>One</p><p>Two</p><p>Three</p></div>";
    string C = A.Except(B).ToString();
    

    得到结果= <p>Three</p>

    相反,我得到:

    System.Linq.Enumerable+<ExceptIterator>d__73`1[System.Char]
    

    编辑:

    只需使用最大的字符串 除了 最小字符串,颠倒数组顺序:

    string C = B.Except(A);
    

    Nick's new string(C.ToArray()); 给我:

    hr
    

    在使用相反的方法后,有点出乎意料的结果。

    4 回复  |  直到 7 年前
        1
  •  5
  •   Ciprian Vilcan    7 年前

    你的解决方案有两个问题。

    ToString()的行为

    ToString 了解更多信息。

    var C = new string(A.Except(B));
    


    A.的行为,除了(B)

    Except方法并不像你想象的那样工作。

    以下面的代码为例:

    var a = new List<int> { 1, 2, 3 };
    var b = new List<int> { 2, 3, 4 };
    var c = a.Except(b);
    

    结果是{1}。该方法有效地做的是返回a中存在但b中不存在的所有int的新枚举。

    var A = "<div><p>One</p><p>Two</p></div>";
    

    从LINQ的角度来看,相当于

    var A = new List<char> { '<', 'd', 'i', 'v', '>', ..., '<', '/', 'd', 'i', 'v', '>' };
    



    所以,当你做A.Except(B)时,LINQ实际上要做的是遍历每个字符,看看它是否能在B中找到它。如果它找到了,它就不会出现在结果集中。既然A中的所有字符都存在于B中,那么将得到一个空字符串。要查看实际情况,请稍微修改A,使其包含不在B中的字符:

    string A = "<div><p>One</p><p>Two</p></div>ApplePie";
    

    如果你现在这样做

    string A = "<div><p>One</p><p>Two</p></div>ApplePie";
    string B = "<div><p>One</p><p>Two</p><p>Three</p></div>";
    string C = new string(A.Except(B).ToArray());
    

    你会得到“阿尔卑斯山”。

    在我看来,执行except的最好方法是解析字符串,将它们转换为对象,然后执行except。没有内置的算法能够告诉您的字符串实际上是结构化的,以及如何区分它们。作为一个有效的解决方案,使用 HtmlAgilityPack (a nuget package)

    var docB = new HtmlDocument();
    docB.LoadHtml(B);
    
    var docA = new HtmlDocument();
    docA.LoadHtml(A);
    var nodes = docB.DocumentNode.FirstChild.Descendants("p").Select(node => node.InnerHtml)
        .Except(docA.DocumentNode.FirstChild.ChildNodes.Select(node => node.InnerHtml));
    // take note that we are actually doing whatIsInB.Except(whatIsInA), since doing the reverse would result in nothing. There is no &lt;p&gt; in A that is not also present in B
    
    var result = string.Join(Environment.NewLine, nodes); // will resut in "Three"
    var otherResult = $"<p>{result}</p>"; // "<p>Three</p>"
    

    我会让你做一个更一般的方法:)
    但这个想法是,如果你想按照你期望的方式工作,你就必须要求它使用字符串,而不是字符。



        2
  •  1
  •   andre    7 年前

    当使用Except()扩展方法时,返回类型是一个Char列表。

    Documentation

    另外,A.Excepts(B)永远不会产生您想要的结果,因为它将字符串转换为char数组。因此,它将从A中删除B中存在的每个char。

        3
  •  0
  •   Guillermo Gutiérrez    7 年前

    你想要的不是 Except ,因为它是一个名为 set difference or relative complement ,其中,您希望某个集合中的元素不存在于另一个集合中。

    你可以达到你期望的结果 regular expressions groups

    using System;
    using System.Text.RegularExpressions;
    
    class Program
    {
        static void Main()
        {
            // Input string.
            string input = "<div><p>One</p><p>Two</p><p>Three</p></div>";
    
            // Use named group in regular expression.
            Regex expression = new Regex(@"^<div><p>One</p><p>Two</p>(?<middle>[<>/\w]+)</div>$");
    
            // See if we matched.
            Match match = expression.Match(input);
            if (match.Success)
            {
                // Get group by name.
                string result = match.Groups["middle"].Value;
                Console.WriteLine("Middle: {0}", result);
            }
    
            // Done
            Console.ReadLine();
        }
    }
    

    使用正则表达式 ^<div><p>One</p><p>Two</p>(?<middle>[<>/\w]+)</div>$ 你说弦应该开始( )与 <div><p>One</p><p>Two</p> ,结束( $ </div> ,而这两者之间包含 < , > / ,或任何字母数字字符( \西 )不止一次( ),将添加到名为 中间的

    不过,我不建议你 try to parse HTML with regex

        4
  •  -2
  •   Nick    7 年前

    使用 string C = new string (A.Except(B).ToArray());