搜索单词而不是字符串?

Posted

技术标签:

【中文标题】搜索单词而不是字符串?【英文标题】:Searching for a word and not a string? 【发布时间】:2019-08-29 19:31:12 【问题描述】:

我想检查一个文件中的特定单词,我在各种论坛上发现的方法是使用以下代码...

Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If content.Contains("stringToSearch") Then
    'Do your stuff
End If

这没关系,直到您发现它会搜索和匹配复合词等。例如,如果我在文件中搜索字符串light,但它不存在,而是单词lightning,它仍然会注册为找到匹配项......有没有办法使用VB找到和准确的单词.net?

【问题讨论】:

您可能会在 regular expression 中找到单词边界 anchor \b 对此很有用。 如果我理解正确,会像下面这样? If content.Contains("\bstringToSearch\b") 那么 更像If Regex.Match(Regex.Match(stringToSearch, "\bstringToSearch\b", RegexOptions.IgnoreCase)(最后一部分只是一个建议) 难道你不能在用户搜索词的每一端附加一个空格,使其成为一个词搜索吗? ...content.contains(" " & stringtosearch & " ") @CharlesMay 考虑一下,如果搜索的单词是文件中的第一个单词,或者在句子的末尾,然后是句号,这是否可行。 【参考方案1】:

执行此操作的最短和最快方法是将ReadLines 与 LINQ 查询结合使用,特别是在处理大文件时。

Dim myword As String = "Book"
Dim reg = New Regex("\b" & myword & "\b", RegexOptions.IgnoreCase)
Dim res = From line In File.ReadLines(largeFileName)
                  Where reg.IsMatch(line)

如果您的文件包含“Book”、“Books”、“Book”。和“书”,结果将是:

Book
Book,
Book.

您可以按以下方式处理结果

TextBox1.Text = resLines.Count

或者

TextBox1.Text = resLines(0)

经过编辑使其符合“。”和“,”等

【讨论】:

@Çöđěxěŕ LINQ 使它成为最短的方式,ReadLines 使它成为我提到的专门处理大文件的最快方式,请在投票前阅读 ReadLines 和 LINQ 的文档! "通过使用查询语法,您可以使用 *最少 的代码对数据源执行过滤、排序和分组操作。"* docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… “因此,当您处理非常大的文件时,ReadLines 可以更高效。” docs.microsoft.com/en-us/dotnet/api/… I understand 我希望! see if a word exist 存在于哪里?在一个文件中?那么如何在不读取文件中的每个单词的情况下搜索文件中的单词呢?答案是你不能,所以你需要以一种有效的方式读取文件中的所有行,这正是我们使用 ReadLines 的原因。 现在你已经在这里删除了所有的 cmets :) 这无关紧要,讨论时间很长。在这种情况下,史蒂文的答案是最好的。【参考方案2】:

另一种方法,使用Regex.Matches,它允许搜索单词集合并返回Dictionary(Of String, Integer())

字典 Key 将匹配的单词 Value 表示为整数数组,即在文件中找到该单词的所有位置。

扩展方法需要2个参数: - 要搜索的文件路径 - 一个布尔值,用于指定搜索是否应区分大小写。

建议作为IEnumerable(Of String)的扩展方法:

Dim fileName As String = "[File Path]"
Dim searchWords As String() = "light", "lighting", "clip", "clipper", "somethingelse"
Dim result = searchWords.FindWords(fileName, False)

打印找到的匹配结果:

result.ToList().ForEach(
    Sub(w)
        Console.WriteLine($"Word: w.Key Positions: String.Join(", ", w.Value)")
    End Sub)

扩展方法:

Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Text
Imports System.Text.RegularExpressions

Module modIEnumerableExtensions

    <Extension()>
    Public Function FindWords(words As IEnumerable(Of String),
                              fileName As String,
                              caseSentive As Boolean) As Dictionary(Of String, Integer())
        Dim pattern As StringBuilder = New StringBuilder()
        pattern.Append(String.Concat(words.Select(Function(w) $"\bw\b|")))

        Dim options As RegexOptions = RegexOptions.Compiled Or
            If(caseSentive, RegexOptions.Multiline, RegexOptions.IgnoreCase Or RegexOptions.Multiline)

        Dim regx As New Regex(pattern.ToString().TrimEnd("|"c), options)
        Dim matches As MatchCollection = regx.Matches(File.ReadAllText(fileName))

        Dim groups = matches.OfType(Of Match).
            GroupBy(Function(g) g.Value).
            ToDictionary(Function(g) g.Key, Function(g) g.Select(Function(m) m.Index).ToArray())
        Return groups
    End Function
End Module

【讨论】:

【参考方案3】:

正如 Andrew Morton 所提到的,Regex 使这种事情变得非常容易。例如,如果您制作了这样的函数:

Public Function ContainsWord(input As String, word As String) As Boolean
    Return Regex.IsMatch(input, $"\bword\b")
End Function

你可以这样使用它:

Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If ContainsWord(content, "stringToSearch") Then
    'Do your stuff
End If

如果您愿意,您甚至可以在 String 类型上将其设为 extension method,方法是将其放入模块并添加 ExtensionAttribute,如下所示:

<Extension>
Private Function ContainsWord(input As String, word As String) As Boolean
    Return Regex.IsMatch(input, $"\bword\b")
End Function

然后你可以这样称呼它:

Dim content = My.Computer.FileSystem.ReadAllText(filePath)
If content.ContainsWord("stringToSearch") Then
    'Do your stuff
End If

【讨论】:

以上是关于搜索单词而不是字符串?的主要内容,如果未能解决你的问题,请参考以下文章

执行查询搜索以匹配字符而不是确切的单词。

在字符串中提取围绕给定搜索字符串的 X 个单词

Javascript在字符串中查找单词的索引(不是单词的一部分)

如何搜索字符串以查看我是不是可以拼写单词

如何确保 replaceAll 将替换整个单词而不是子字符串

使用二进制搜索的 Java 前缀搜索