【问题标题】:How to get context of a sentence如何获取句子的上下文
【发布时间】:2019-11-13 09:09:07
【问题描述】:

所以我正在开发一个可以修补损坏的单词的应用程序。

让我们来:

很多人说这句话有错误

在这里,我们可以使用 swift UITextChecker 并获得 mny 这个词实际上可能是什么的美妙结果......但是,我实际上有几个选择,其中一个是 many 和其中一个其他你有money,所以显然钱在这句话中不太适合。有什么方法可以检查句子本身是否合乎逻辑?

【问题讨论】:

  • 没有理由拒绝投票或“关闭”很好..谢谢
  • 没有内置的方法来检查句子的正确性。您需要自己创建该逻辑或使用第三方 API,例如 grammarbot.io
  • 你问的问题很重要。检查这个开源项目github.com/languagetool-org/languagetool
  • @SahilManchanda @AlekseyPotapov 谢谢你们。我在UITextCheckerNaturalLanguageToolkit 都用swift 语言查看了一些,并认为你可以用它来发挥一些神奇的作用。但这似乎是不可能的。
  • 还是可以的。在考虑你的问题时,我很想浏览互联网,我想到了这个想法,当你使用 UITextChecker 和 NLTagger 时,我所能得到的只是这样的:拼写错误:mny 建议:可选([“可能”,“任何” , "my", "many"]) mny: 形容词 people: 名词 say: 动词 there: 代词 is: 动词 an: 限定词 error: 名词 in: 介词 this: 限定词句: 名词 ---- may: 名词 any: 限定词my: OtherWord many: 形容词

标签: swift string nlp spell-checking uitextchecker


【解决方案1】:

认为这仍然需要改进。我将this swift 3 解决方案更新为Swift 5。值得一提的是,它最初的灵感来自this python tutorial

创建一个新的 iOS 项目,在其中添加一个名为 bigtext.txt 的文本文件,其中包含 this text。这将是我们的“学习”词典。 然后在ViewController:

import UIKit
import NaturalLanguage

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let inputString = "mny people say there is a error in this sentence"
        var newString = inputString

        // Read a text file and "study" the model
        guard let path = Bundle.main.path(forResource: "bigtext", ofType: "txt") else {
            print("Path not available")
            return
        }
        let checker = SpellChecker(contentsOfFile: path)

        // better to use this to iterate between words in a sentence
        let tokenizer = NLTokenizer(unit: .word)
        tokenizer.string = inputString
        tokenizer.enumerateTokens(in: inputString.startIndex..<inputString.endIndex) { tokenRange, _ in
            let word = String(inputString[tokenRange])
            let checked = checker?.correct(word: word)
            let candidates = checker?.candidates(word: word)

            if word == checked {
                print("\(word) unchanged")
            } else {
                if let checked = checked {
                    newString.replaceSubrange(tokenRange, with: checked)
                }
                print("Correct:\t\(word) -> \(String(describing: checked))")
                print("Candidates:\t\(word) -> \(String(describing: candidates))")
            }
            return true
        }
        print("Result: \(newString)")
    }
}

func edits(word: String) -> Set<String> {
    if word.isEmpty { return [] }

    let splits = word.indices.map {
        (word[word.startIndex..<$0], word[$0..<word.endIndex])
    }

    let deletes = splits.map { $0.0 +  String($0.1.dropFirst()) }

    let transposes: [String] = splits.map { left, right in
        if let fst = right.first {
            let drop1 = String(right.dropFirst())
            if let snd = drop1.first {
                let drop2 = String(drop1.dropFirst())
                return "\(left)\(snd)\(fst)\(drop2)"
            }
        }
        return ""
    }.filter { !$0.isEmpty }

    let alphabet = "abcdefghijklmnopqrstuvwxyz"

    let replaces = splits.flatMap { left, right in
        alphabet.map { "\(left)\($0)\(String(right.dropFirst()))" }
    }

    let inserts = splits.flatMap { left, right in
        alphabet.map { "\(left)\($0)\(right)" }
    }
    let setString = [String(deletes.first!)] + transposes + replaces + inserts
    return Set(setString)
}

struct SpellChecker {

    var knownWords: [String:Int] = [:]

    mutating func train(word: String) {
        if let idx = knownWords[word] {
            knownWords[word] = idx + 1
        }
        else {
            knownWords[word] = 1
        }
    }

    init?(contentsOfFile file: String) {
        do {
            let text = try String(contentsOfFile: file, encoding: .utf8).lowercased()
            let words = text.unicodeScalars.split(whereSeparator: { !("a"..."z").contains($0) }).map { String($0) }
            for word in words { self.train(word: word) }
        }
        catch {
            return nil
        }
    }

    func knownEdits2(word: String) -> Set<String>? {
        var known_edits: Set<String> = []
        for edit in edits(word: word) {
            if let k = known(words: edits(word: edit)) {
                known_edits.formUnion(k)
            }
        }
        return known_edits.isEmpty ? nil : known_edits
    }

    func known<S: Sequence>(words: S) -> Set<String>? where S.Iterator.Element == String {
        let s = Set(words.filter { self.knownWords.index(forKey: $0) != nil })
        return s.isEmpty ? nil : s
    }

    func candidates(word: String) -> Set<String> {
        guard let result = known(words: [word]) ?? known(words: edits(word: word)) ?? knownEdits2(word: word) else {
            return Set<String>()
        }

        return result
    }

    func correct(word: String) -> String {
        return candidates(word: word).reduce(word) {
            (knownWords[$0] ?? 1) < (knownWords[$1] ?? 1) ? $1 : $0
        }
    }
}

会输出你:

Correct:    mny -> Optional("may")
Candidates: mny -> Optional(Set(["any", "ny", "may", "many"]))
people unchanged
say unchanged
there unchanged
is unchanged
a unchanged
error unchanged
in unchanged
this unchanged
sentence unchanged
Result: may people say there is a error in this sentence

请考虑我们选择了第一个更正候选人。 首先需要理清词序,理解句子的上下文。

【讨论】:

  • 对,这么多,可能都适合这个。而这个会选择可能吗?我猜“可能”会产生一个问题?但我想同时,它和我曾经得到的一样接近..
  • 这里似乎都有效。这个可以提供候选人,与他们一起你可以继续。我认为,可以使用另一种类型的文本来“训练”模型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2020-08-30
  • 2016-08-22
  • 1970-01-01
相关资源
最近更新 更多