【问题标题】:VB.NET - List.Contains Returns False But Should be TrueVB.NET - List.Contains 返回 False 但应该为 True
【发布时间】:2016-12-05 13:55:27
【问题描述】:

我查看了List.Contains returns false, even though it seems it should return true,但他的代码结构与我的有点不同,所以我不确定我是否有同样的问题。

在我继续之前,让我解释一下我的结果应该是什么。 我们有 2 个输入文件,文件 1 带有 email:hash,另一个带有 email:hashemail:plain 的混合。

结束输出:如果第二个文件在 : 之后有明文,则输出它(确保在输出文件 1 的电子邮件时不重复:如果没有为该电子邮件/哈希生成文件 2 行,则确保不重复),否则输出哈希.

tl;dr - 基本上将第二个文件 overwrite prioritized 放在第一个文件之上。

(First File Randomized)
ABC_123@gmail.com:f6deea50e7eeb2d930fab83ccc32cdfe
123abc@domain.ext:82e6eeea4060c90cc3dc6ddd25885806
123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd
abc123@email.com:2d366131008f89781b8379bed3451656

(Second File Randomized)
123abc@domain.ext:aaaaaaaa
ABC_123@gmail.com:cccccccc
abc123@email.com:bbbbbbbb
newemail@hotmail.com:ddddddddd

Output should be:
123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd
123abc@domain.ext:aaaaaaaa
ABC_123@gmail.com:cccccccc
abc123@email.com:bbbbbbbb
newemail@hotmail.com:ddddddddd

(Output from Tests - "->" lines shouldn't be outputted.)
123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd
->123abc@domain.ext:82e6eeea4060c90cc3dc6ddd25885806
123abc@domain.ext:aaaaaaaa
ABC_123@gmail.com:cccccccc
->ABC_123@gmail.com:f6deea50e7eeb2d930fab83ccc32cdfe
abc123@email.com:bbbbbbbb
newemail@hotmail.com:ddddddddd

在第二个 OpenFileDialog 块中,它始终返回 false,直到 For Each combo as Match in matches 中的最后一行。 奇怪的是,如果我将第二个正则表达式从 (.*)@(.*):(.*) 更改为 (.*)@(.*):([a-f0-9]{32}) 出于某种原因它会起作用,问题是它只会匹配 Email@domain.ext:{md5} 而不会匹配例如 Email@domain.ext:abc123 这是一个要求。
(最新的代码更新,我一直在搞乱尝试修复它,它更破坏了它,所以现在这甚至不起作用)。

我睡了一次然后回来尝试修复它,到目前为止我几乎在那里,它正在正确覆盖,除了一封电子邮件:出于某种原因哈希。

Image showing error 如您所见,它将 123abc@domain.ext 从哈希更改为 aaaaaaa,但对于 ABC_123@gmail.com,它并没有出于某种奇怪的原因。同样是的,abc123@email.com 哈希确实发生了变化,所以奇怪的是随机 email:hash 没有改变。

我已经连续 12 多个小时在此工作了大约 9。 (毫不夸张),我真的很想了解正在发生的事情。

我已经尝试了很多替代方法,以至于我现在都记不起来了。

代码:(更新 x3)
提醒:阅读上面关于我试图实现的目标:)

#Region "Merge Combo's"

    Private Sub List_Merge_Click(sender As Object, e As EventArgs) Handles List_Merge.Click

        Dim ofd = New OpenFileDialog()
        ofd.Title = "Import..."
        ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
        ofd.Filter = "Text files|*.txt"
        ofd.Multiselect = True

        'If the user selects 2 Files;
        If (ofd.ShowDialog() = DialogResult.OK And ofd.CheckFileExists = True) Then

            'Make sure there are no previously stored Conversions;
            ActionList2.Items.Clear()

            'Variables;
            Dim MergedCombos As Integer = 0
            Dim TotalCombos As Integer = 0

            Try

                For Each filename As String In ofd.FileNames

                    Using sr As New StreamReader(filename)

                        Dim result = filename.Union(filename, New MailEqualityComparer)

                        'Get all Matches found from the Regex Condition;
                        Dim combos As MatchCollection = New Regex("^([^@]+)@(.*):(.*)$", RegexOptions.Multiline).Matches(sr.ReadToEnd)

                        'Add each Match to the ActionList except for Duplicates;
                        For Each combo As Match In combos

                            'Increment the Total Combo's count;
                            TotalCombos += 1

                            'If the ActionList doesn't contain the same Combo;
                            If Not ActionList2.Items.Contains(combo.Value) Then

                                'If the email is already in the ActionList;
                                If IsInListbox(ActionList2, combo.Groups(1).Value + "@" + combo.Groups(2).Value) = True Then

                                    'This combo is presumed to be a Hash Decrypted Combo - Overwrite it with the Encrypted Hash;
                                    ActionList2.Items.Add(combo.Value)

                                    'Remove the Hash Item from ActionList;
                                    ActionList2.Items.RemoveAt(FindListboxIndex(ActionList2, combo.Groups(1).Value + "@" + combo.Groups(2).Value))

                                Else

                                    'Add the Combo;
                                    ActionList2.Items.Add(combo.Value)

                                End If

                            End If

                        Next

                    End Using

                Next

            Catch ex As Exception

                Console.WriteLine("Error: " + ex.ToString)

            Finally

                'If atleast 1 Item is in the ActionList, Enable the Export Button;
                If ActionList2.Items.Count > 0 Then
                    ExportButton.Enabled = True
                    ExportButton.BackColor = Color.FromArgb(149, 255, 141)
                End If

                'Update the Merged Combo's count;
                StatusBar_LeftText.Text = MergedCombos.ToString

                'If MergedCombos are less than TotalCombos, Add a "x Duplicates Removed" message;
                If MergedCombos < TotalCombos Then
                    StatusBar_LeftText.Text += " - " + (TotalCombos - MergedCombos).ToString + " Duplicates Removed"
                End If

                'Autoscroll;
                ActionList2.TopIndex = ActionList2.Items.Count - 1

            End Try

        End If

    End Sub

    Private Function FindListboxIndex(lb As ListBox, searchString As String) As Integer
        For i As Integer = 0 To lb.Items.Count - 1
            If lb.Items(i).ToString().Contains(searchString) Then
                Return i
                Exit Function
            End If
        Next
        Return -1
    End Function

    Private Function IsInListbox(lb As ListBox, searchString As String) As Boolean
        For i As Integer = 0 To lb.Items.Count - 1
            If lb.Items(i).ToString().Contains(searchString) Then
                Return True
                Exit Function
            End If
        Next
        Return False
    End Function

#End Region

【问题讨论】:

  • 没人评论吗?有什么你们认为我应该尝试的吗?测试?等等?没有? o.o
  • 如果你们找不到帮助的方法 - 请为我的问题投票,因为这就是它的目的,投票将帮助其他人找到我的问题 = 更多答案/建议的可能性!谢谢
  • 仍然需要答案 - 上面的代码应该可以工作,但由于某种原因它并不总是有效。

标签: vb.net visual-studio visual-studio-2015


【解决方案1】:

您好,我认为这应该符合您的需求。

    Dim ofd = New OpenFileDialog()
    ofd.Title = "Import..."
    ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    ofd.Filter = "Text files|*.txt"
    ofd.Multiselect = True

    Dim output As New Dictionary(Of String, String) 'key = mail, value = plain/hash

    If (ofd.ShowDialog() = DialogResult.OK And ofd.CheckFileExists = True) Then

        For Each filename As String In ofd.FileNames
            Using sr As New StreamReader(filename)

                Dim combos As MatchCollection = New Regex("(.*)@(.*):(.*)").Matches(sr.ReadToEnd)

                For Each match As Match In combos
                    Dim tmp() As String = Split(match.ToString, ":")
                    tmp(1) = tmp(1).Replace(vbCr, "").Replace(vbLf, "") 'Delete carriage return
                    If Not output.ContainsKey(tmp(0)) Then
                        output.Add(tmp(0), tmp(1))
                    Else
                        If output(tmp(0)).Length = 32 Then 'condition whether to change the value or not. You need to design it to your needs.
                            output(tmp(0)) = tmp(1)
                        End If
                    End If
                Next match
            End Using

        Next filename
    End If

我不知道你的数据中是否有回车。我尝试使用简单的 txt 文件,并且有。 您需要根据需要更改条件。我看到哈希有 32 个符号,而纯文本没有..

【讨论】:

  • 问题是,文件顺序可能不同。所以 file1() 可能有 file2() 的内容,所以这真的行不通吗?
  • 这就是我从file2开始的原因。这意味着来自 file2 的所有数据都被放入字典中。这意味着所有 email:plain 都已存储。然后打开 file1 并检查电子邮件是否可用。如果没有,请添加电子邮件:哈希。如果是,请不要添加,因为您想要 email:plain。我认为这应该有效。它适用于您给定的输入示例。
  • 正如我所说,您的示例不起作用,文件顺序可能会有所不同,具体取决于用户选择和打开文件的方式
  • 我明白了。如何检查字符串是散列还是纯文本?
【解决方案2】:

你想要的是你拥有的两组线的联合,这正是Enumerable.Union 所做的,只要我们有一种方法来区分相等的元素。

从这里开始,我们首先定义相等比较器:

Class MailEqualityComparer
    Implements IEqualityComparer(Of String)

    Overloads Function Equals(mail1 As String, mail2 As String) As Boolean Implements IEqualityComparer(Of String).Equals
        ' assume input validated
        Return mail1.Split(":"c)(0).Equals(mail2.Split(":"c)(0))
    End Function

    Overloads Function GetHashCode(mail As String) As Integer Implements IEqualityComparer(Of String).GetHashCode
        ' assume input validated
        Return mail.Split(":"c)(0).GetHashCode
    End Function
End Class

对于这个类,如果: 之前的部分相等,则两个字符串相等。

然后你只需要使用该类的一个实例进行联合来确保正确的相等性:

    ' file1 and file2 are String arrays
    ' they could be the result of File.ReadAllLines for example

    Dim file1 = {
        "ABC_123@gmail.com: f6deea50e7eeb2d930fab83ccc32cdfe",
        "123abc@domain.ext:82e6eeea4060c90cc3dc6ddd25885806",
        "123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd",
        "abc123@email.com: 2d366131008f89781b8379bed3451656"
    }

    Dim file2 = {
        "123abc@domain.ext: aaaaaaaa",
        "ABC_123@gmail.com: cccccccc",
        "abc123@email.com: bbbbbbbb",
        "newemail@hotmail.com: ddddddddd"
    }

    ' result is an IEnumerable(Of String)
    ' add ToArray (for example) if you want to materialize the result
    Dim result = file2.Union(file1, New MailEqualityComparer) ' note the order ; it matters

    ' result content :
    ' ----------------
    ' 123abc@domain.ext: aaaaaaaa
    ' ABC_123@gmail.com: cccccccc
    ' abc123@email.com: bbbbbbbb
    ' newemail@hotmail.com: ddddddddd
    ' 123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd

它只是给我们留下了“我们如何确定联合参数的顺序?”
为此,我们必须有办法知道哪个文件包含“纯文本”内容,即您在撰写本文时未提供的信息。

(注意:使用Hashset(Of String)SortedSet(Of String) 及其UnionWith 方法也可以实现同样的效果)
[SortedSet 需要IComparer(Of String) 而不是IEqualityComparer(Of String)]

评论后编辑

如果我正确理解了您的评论(我不确定);这是使用 SortedSet 可以完成的事情:

Class MailComparer
    Implements IComparer(Of String)

    Function Compare(mail1 As String, mail2 As String) As Integer Implements IComparer(Of String).Compare
        ' assume input validated
        Return mail1.Split(":"c)(0).CompareTo(mail2.Split(":"c)(0))
    End Function
End Class

' file1 and file2 are String arrays
' they could be the result of File.ReadAllLines for example
Dim file1 = {
    "ABC_123@gmail.com: f6deea50e7eeb2d930fab83ccc32cdfe",
    "123abc@domain.ext:82e6eeea4060c90cc3dc6ddd25885806",
    "123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd",
    "abc123@email.com: 2d366131008f89781b8379bed3451656"
}

Dim file2 = {
    "123abc@domain.ext: aaaaaaaa",
    "ABC_123@gmail.com: cccccccc",
    "abc123@email.com: bbbbbbbb",
    "newemail@hotmail.com: ddddddddd"
}

' allLines is an IEnumerable(Of String)
Dim allLines = file2.Concat(file1) ' note the order ; it matters

Dim result As New SortedSet(Of String)(allLines, New MailComparer)

' result content :
' ----------------
' 123_ABC@gmail.com:8fa5104d4d995dc153e5509ab988bcfd
' 123abc@domain.ext: aaaaaaaa
' ABC_123@gmail.com: cccccccc
' abc123@email.com: bbbbbbbb
' newemail@hotmail.com: ddddddddd

我看不出使用 8 行类有什么不简单的地方;但也许我错过了重点......

【讨论】:

  • 好的,我将如何设法使用 Hashset/Sortedset 对列表进行适当的排序?
  • 更简单的方法是为此使用 SortedSet(HashSet 没有排序的概念)并创建一个实现 IComparer(Of String) 的类(如MailEqualityComparer)以提供它的构造函数。在该类中,Compare 方法将负责排序,您必须编写代码来比较两个输入(此处为两个字符串)并返回 -1、0、1 以表示两者之间的相对顺序。
  • ... 另一种可能的方法是创建一个类型来存储您的输入(将电子邮件部分和哈希/文本部分分成两个单独的字段)并且该类可以实现 IComparable(Of TheClass) 允许比较它们之间实例的方法(如果您打算将这些字符串用于更多事情,可能还有其他操作)
  • 老实说,在这一点上我迷失了:/您能否在 OP 中查看我的代码,或许可以对其进行编辑以进行编辑?
  • 你真的不明白,就像它识别它们并用纯文本覆盖就好了,除了一个奇怪的哈希。是否有必要使用所有这些新的类/函数等?肯定有更简单的方法
猜你喜欢
  • 2014-04-24
  • 2011-01-18
  • 2013-02-23
  • 1970-01-01
  • 2014-10-21
  • 2020-02-12
  • 2016-04-16
  • 1970-01-01
  • 2019-03-29
相关资源
最近更新 更多