You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Golang中检查文本是否含列表词汇?代码类型不匹配问题求解

解决Golang中检测文本是否包含垃圾词汇的问题

嘿,我来帮你梳理下代码里的问题,再给出几个更地道的实现方式~

你的代码核心问题

首先看你遇到的runestring类型不匹配的错误,根源是遍历文本的方式错了

  • for _, word := range text 会逐个取出字符串中的单个字符(rune类型),而不是你想要的"单词";
  • 另外还有两个小问题:变量名拼写错误(sapmWord应该是spamWord),以及函数没有默认返回值(遍历完所有内容没找到垃圾词时,需要返回false)。

基础修复版本

先把这些问题修正,同时保留你去除标点的需求,代码如下:

import (
    "sort"
    "strings"
)

func TextHasSpamWords(text string, spamWords []string) bool {
    // 定义去除标点的映射函数
    removePunctuation := func(r rune) rune {
        if strings.ContainsRune(".,:;", r) {
            return -1
        }
        return r
    }

    // 1. 去除文本中的标点,同时转小写(可选,实现大小写不敏感匹配)
    processedText := strings.ToLower(strings.Map(removePunctuation, text))
    // 2. 按空白符分割成单词列表
    words := strings.Fields(processedText)

    // 排序垃圾词,用二分查找优化遍历效率
    sort.Strings(spamWords)

    // 遍历每个处理后的单词,检查是否在垃圾词列表中
    for _, word := range words {
        // 二分查找替代逐个遍历,效率更高
        idx := sort.SearchStrings(spamWords, word)
        if idx < len(spamWords) && spamWords[idx] == word {
            return true
        }
    }

    // 没找到任何垃圾词,返回false
    return false
}

更地道高效的实现(推荐)

当垃圾词数量较多时,用切片遍历的效率会很低。更符合Golang风格的做法是把垃圾词存入map作为查找表,这样查找操作的时间复杂度是O(1):

import (
    "strings"
)

func TextHasSpamWords(text string, spamWords []string) bool {
    // 初始化垃圾词查找map,用空结构体节省内存
    spamMap := make(map[string]struct{}, len(spamWords))
    for _, word := range spamWords {
        // 垃圾词也转小写,和文本处理逻辑保持一致
        spamMap[strings.ToLower(word)] = struct{}{}
    }

    removePunctuation := func(r rune) rune {
        if strings.ContainsRune(".,:;", r) {
            return -1
        }
        return r
    }

    processedText := strings.ToLower(strings.Map(removePunctuation, text))
    words := strings.Fields(processedText)

    // 遍历单词,用map快速判断是否为垃圾词
    for _, word := range words {
        if _, exists := spamMap[word]; exists {
            return true
        }
    }

    return false
}

进阶:精确单词边界匹配

如果需要避免"部分匹配"的问题(比如垃圾词是bad,不想把badly误判为垃圾内容),可以用正则表达式实现单词边界匹配:

import (
    "regexp"
    "strings"
)

func TextHasSpamWords(text string, spamWords []string) bool {
    // 构造正则模式:给每个垃圾词加上单词边界,同时转义特殊字符避免正则注入
    patterns := make([]string, len(spamWords))
    for i, word := range spamWords {
        escapedWord := regexp.QuoteMeta(word)
        patterns[i] = "\\b" + escapedWord + "\\b"
    }

    // 正则模式:(?i)表示不区分大小写,|表示或逻辑
    regexPattern := "(?i)" + strings.Join(patterns, "|")
    re := regexp.MustCompile(regexPattern)

    // 先去除文本标点
    removePunctuation := func(r rune) rune {
        if strings.ContainsRune(".,:;", r) {
            return -1
        }
        return r
    }
    processedText := strings.Map(removePunctuation, text)

    // 检查是否匹配任意垃圾词
    return re.MatchString(processedText)
}

总结

  • 基础错误是混淆了"字符遍历"和"单词遍历",用strings.Fields()可以正确分割文本为单词;
  • 用map做查找表是Golang中处理这类存在性检查的最优方案,效率更高;
  • 正则表达式适合需要精确边界匹配的场景,但要注意垃圾词过多时的性能问题。

内容的提问来源于stack exchange,提问作者Smn

火山引擎 最新活动