【问题标题】:How to use autocorrection and shortcut list in iOS8 custom keyboard?如何在 iOS 8 自定义键盘中使用自动更正和快捷键列表?
【发布时间】:2014-08-28 22:34:09
【问题描述】:

我想在我的自定义键盘上使用自动更正和快捷方式列表,例如默认英文键盘。 我检查了输入键盘文档,但不知道如何使用它。

keyboard documentation

每个自定义键盘(与其 RequestsOpenAccess 键的值无关)都可以通过 UILexicon 类访问基本的自动更正词典。利用这个类以及您自己设计的词典,在用户输入文本时提供建议和自动更正。 UILexicon 对象包含来自各种来源的单词,包括:

  • 用户通讯簿数据库中的名字和姓氏不成对
  • 在“设置”>“常规”>“键盘”>“快捷方式”列表中定义的文本快捷方式
  • 常用词词典

如何在 Objective-C 中从我们的字典中访问快捷方式列表和输入?

如何将 UILexicon 与 requestSupplementaryLexiconWithCompletion 一起使用?

【问题讨论】:

  • @rickster 有一个绝妙的答案here。你看过吗?我无法理解其他人应得的 500 分赏金,因为答案已经存在。
  • 谢谢@remus!也许那个问题已经关闭,所以我无法搜索。

标签: ios objective-c keyboard ios8


【解决方案1】:

实现词典看起来很像这样:

  1. 使用requestSupplementaryLexiconWithCompletion() 在启动时获取词典一次。
  2. 输入每种类型的文字后添加到NSString(跟踪当前单词)
  3. 当用户按空格键(当前单词结尾)时,对照词典检查字符串
  4. 如果匹配,则计算字符数并删除该字符数
  5. 输入词典建议的建议
  6. 清除字符串并重新开始

此外,您还可以使用UITextChecker 来提供更高级的自动更正功能。

代码(在 Objective-C 中,这可能不是我在公交车上用 SO 编写的 100% 准确,但应该可以):

UILexicon *lexicon;
NSString *currentString;

-(void)viewDidLoad {
     [self requestSupplementaryLexiconWithCompletion:^(UILexicon *receivedLexicon) {
         self.lexicon = receivedLexicon;
     }];
}

-(IBAction)myTypingAction:(UIButton *)sender {
    [documentProxy insertText:sender.title]; 
    [currentString stringByAppendingString:sender.title];
}

-(IBAction)space {
   [documentProxy insertText:@" "];
   for (UILexiconEntry *lexiconEntry in lexicon.entries) {
       if (lexiconEntry.userInput isEqualToString:currentString) {
            for (int i = 0; currentString.length >=i ; i++) { 
                 [documentProxy deleteTextBackwards];
            }
            [documentProxy insertText:lexiconEntry.documentText];
            currentString = @"";  
        }
    } 
}

如果您还有任何问题,请随时发表评论。

来源:iOS 8 键盘和 UILexicon 的个人体验

【讨论】:

  • 如果它匹配一个自动更正的词,那你为什么要删除它然后应用同一个词? Entries 是一个错误单词列表,还是如何将错误单词变为正确单词?
  • Entries 是一个单词列表,如果输入了其他单词,则应替换这些单词,例如:我输入了 sry,它会将其更正为 sorry,因为那是我定义为快捷方式的内容。这些条目不用于自动更正。
  • 它是自动更正的一部分,但不是最先进的类型。
  • 这太棒了,我似乎遇到的唯一麻烦是这个词典中的所有字符串都以小写形式返回(包括联系人姓名)。有没有办法获取每个字符串的原始大小写,或者我们应该根据我们的需要调整它(即myString = myLexiconEntry.documentText.capitalizedString
  • 哦,如果这应该在后台线程上完成(不包括对我们 UI 的更新),我在打字时遇到了令人讨厌的延迟...
【解决方案2】:

关于自动更正,我可以使用link 添加它。这是我从链接中使用的代码 sn-p:

UITextChecker *checker = [[UITextChecker alloc] init];

  NSRange checkRange = NSMakeRange(0, self.txView.text.length);

  NSRange misspelledRange = [checker rangeOfMisspelledWordInString:self.txView.text 
                                                             range:checkRange
                                                        startingAt:checkRange.location
                                                              wrap:NO 
                                                          language:@"en_US"];

  NSArray *arrGuessed = [checker guessesForWordRange:misspelledRange inString:self.txView.text language:@"en_US"];

  self.txView.text = [self.txView.text stringByReplacingCharactersInRange:misspelledRange 
                                                               withString:[arrGuessed objectAtIndex:0]];

可以在here找到来自 Apple 的完整文档。

【讨论】:

    【解决方案3】:

    虽然我没有亲自尝试过创建自定义键盘,但我的答案是基于我在文档中看到的内容。

    在您的键盘中,创建一个名为 entries 的属性,类型为 [AnyObject](AnyObjects 数组)。

    在您的 init 方法中,或在您创建键盘的任何位置,调用此方法:

    requestSupplementaryLexiconWithCompletion(completionHandler: {
        lexicon in 
        self.entries = lexicon.entries
    })
    

    我怀疑entries 实际上是一个字符串数组或NSStrings,但它可能是字典或其他类型。对此进行测试时,请先尝试弄清楚 entries 中实际包含的类型,然后再弄清楚您的逻辑。

    我认为目前没有办法获得 Apple 的默认自动更正选项。但是,WWDC talk 提供了有关他们如何在原始 iPhone 操作系统中进行自动更正工作的见解(大约 30 分钟)。

    他提到使用数组的二进制搜索,这让我相信这个数组是排序的。当然,自从第一款 iPhone 问世以来,情况可能会发生很大变化……

    祝你好运找到这个新的 API!

    【讨论】:

    • 当我使用 self.entries.documentText 时,这确实会返回一个字符串的 NSArray ... 但是 NSArray 总共只有 15 个单词,所以我们怎么能在 99 时使用它来自动更正% 的拼写错误的单词甚至不在 UILexicon 中? :o
    • 我还注意到没有办法设置UILexicon的locale
    【解决方案4】:

    这是您实际访问词典单词的方式:

    [self requestSupplementaryLexiconWithCompletion:^(UILexicon *receivedLexicon) {
        self.lexicon = receivedLexicon;
    
        for (UILexiconEntry *word in self.lexicon.entries) {
            // Text to be inserted into a text input object by a custom keyboard, corresponding to the userInput value in the same lexicon entry.
            NSLog(@"%@",word.documentText);
            // Text to match, during user input, to provide appropriate output to a text document from the documentText value in the same lexicon entry.
            NSLog(@"%@",word.userInput);
        }
    }];
    

    【讨论】:

      【解决方案5】:

      Rachits 在 swift 4 中回答上述问题。适用于 iOS 12

      我有这个助手来检查当前要由 UITextChecker 测试的字符串是否不是空格

      func validate(string: String?) -> Bool {
          guard let text = string,
              !text.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).isEmpty else {
                  return false
          }
          return true
      }
      

      文本检查器然后在我的“空格键”、“空格键双击”和“返回”方法中。下面的例子是在我的“Space”方法中

      let textChecker = UITextChecker()
          let currentString = self.textDocumentProxy.documentContextBeforeInput
          if validate(string: currentString) {
              let charSet = NSCharacterSet.whitespacesAndNewlines
              let components = currentString?.components(separatedBy: charSet)
              let lastWord = components?.last
              let checkRange = NSMakeRange(0, lastWord?.count ?? 0)
              let misspelledRange = textChecker.rangeOfMisspelledWord(in: lastWord!, range: checkRange, startingAt: checkRange.location, wrap: false, language: "en_US")
              if misspelledRange.length != 0 {
                  let guessedWord: Array = textChecker.guesses(forWordRange: misspelledRange, in: lastWord!, language: "en_US")!
                  if  guessedWord.count > 0 {
                      var i = 0
                      while (lastWord?.length)! > i {
                          textDocumentProxy.deleteBackward()
                          i += 1
                      }
                      self.textDocumentProxy.insertText(guessedWord[0])
      
                  }
              }
          }
      
      
          self.textDocumentProxy.insertText(" ")
      

      我必须对 Rachits 代码进行两次更改。首先验证 currentString,因为如果您按两次空格键,它会引发异常。其次检查拼写错误的范围是否不是 0,因为这也引发了一个我还没有弄清楚原因的异常。但这对我现在有效。

      【讨论】:

        【解决方案6】:

        每个自定义键盘(与其 RequestsOpenAccess 键的值无关)都可以通过 UILexicon 类访问基本的自动更正词典。利用这个类以及您自己设计的词典,在用户输入文本时提供建议和自动更正。 UILexicon 对象包含来自各种来源的单词,包括:

        用户通讯簿数据库中未配对的名字和姓氏 在设置 > 常规 > 键盘 > 快捷方式列表中定义的文本快捷方式 包含 Apple 产品名称的常用单词词典

        【讨论】:

        【解决方案7】:

        如果有人还在研究这个问题,我发现了一个非常棒的 C++ 预测文本库,名为 Presage。根据演示,它似乎做得很好,但我在尝试将它集成为库时遇到了很多麻烦(请参阅我的问题here)。

        如果有人有任何想法,请告诉我,非常有兴趣让它发挥作用!

        【讨论】:

        • 你能用 Xcode 和 Objc/Swift 运行 Presage 吗?
        【解决方案8】:

        实际上,UILexicon 只是一种获取拼写检查系统不应尝试修复的用户特定字词的方法。可能,最常见的使用方式是填写UITextChecker 的忽略词列表。

        let lexicon: UILexicon = ...
        let checker: UITextChecker = ...
        
        for entry in lexicon.entries {
            if entry.documentText == entry.userInput {
                checker.ignoreWord(entry.documentText)
            }
        }
        

        此外,UILexicon 可以用作自动替换快捷方式的来源,例如 ("omw" = "On my way!"),但在拼写方面它不是自动更正。

        【讨论】:

        • 我认为if entry.documentText == entry.userInput 几乎永远不会是真的:entry.userInput 是快捷方式,entry.documentText 是替换快捷方式的文本。例如,userInput 是“omw”,documentText 是“在路上!”
        • 不,不,并非总是如此。字典(词典)实际上还包含您通讯录中的所有名称(可能还有其他名称)。
        【解决方案9】:

        您可以将以下逻辑用于自动更正,它也适用于 iOS 10

        -(void)didClickAtAlphaNumericKeyboardKey:(NSString *)value {
        
            if ([value isEqualToString:@" "]) {
                    UITextChecker *checker = [[UITextChecker alloc] init];
                    currentString = self.textDocumentProxy.documentContextBeforeInput;
                    NSCharacterSet *charSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
                    NSArray *components = [currentString componentsSeparatedByCharactersInSet:charSet];
                    NSString *lastWord = components.lastObject;
        
                    NSRange checkRange = NSMakeRange(0, lastWord.length);
                    NSRange misspelledRange = [checker rangeOfMisspelledWordInString:lastWord
                                                                               range:checkRange
                                                                          startingAt:checkRange.location
                                                                                wrap:NO
                                                                            language:@"en_US"];
        
                    NSArray *guessedWord = [checker guessesForWordRange:misspelledRange inString:lastWord language:@"en_US"];
        
                    if (guessedWord && guessedWord.count > 0) {
                        for (int i = 0; lastWord.length >i ; i++) {
                            [self.textDocumentProxy deleteBackward];
                        }
                        [self.textDocumentProxy insertText:[guessedWord objectAtIndex:0]];
                    }
            }
        
            [self.textDocumentProxy insertText:value];
        }
        

        【讨论】:

          猜你喜欢
          • 2012-08-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-16
          • 2012-07-16
          • 2014-08-11
          • 2021-02-27
          相关资源
          最近更新 更多