在UITextView中获取当前键入的单词

时间:2014-12-09 13:11:17

标签: ios objective-c uitextview substring nsrange

我想在UITextView中获取当前输入的字词。获取完全输入单词的方法可以在这里UITEXTVIEW: Get the recent word typed in uitextview找到,但是,我希望在输入时获取单词(无论它在哪里键入,开始,中间,结束UITextView )。

我想定义一个单词的定义是一个空白字符后跟字母数字字符,或者如果当前位置(以某种方式用range.location计算)是UITextView的开头,那么接下来是什么up也应该被视为单词。当另一个空格字符跟随时,一个单词就被输入了。

我尝试过:

 - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text`

但是我找到正确的范围时遇到了问题。

简而言之:我需要在UITextView中找到子字符串,其中substring是当前输入的单词。

编辑:因为问题出现了。我使用NSLayoutManager并将NSTextContainer绑定到它,然后将其作为layoutManager传递给NSTextStorage

EDIT2 (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text的主要问题是range.location与指标不同,但总是少1。如果光标位于位置1,键入一个字母后,range.location将返回0.任何方式都可以吗?此外,text的{​​{1}}属性似乎也是1。当文字为UITextView并输出foobar时,我会获得UITextView.text。因此,fooba会返回例外range.location+1

EDIT3 : 也许使用Range {0, 1} out of bounds; string length 0'代替NSTextStorage

更容易获得我想要的结果

5 个答案:

答案 0 :(得分:8)

以下是使用UITextInputUITextInputTokenizer来提供当前正在键入/编辑的单词的骨架结构示例。

- (void) textViewDidChange:(UITextView *)textView {

    NSRange selectedRange = textView.selectedRange;

    UITextPosition *beginning = textView.beginningOfDocument;
    UITextPosition *start = [textView positionFromPosition:beginning offset:selectedRange.location];
    UITextPosition *end = [textView positionFromPosition:start offset:selectedRange.length];

    UITextRange* textRange = [textView.tokenizer rangeEnclosingPosition:end withGranularity:UITextGranularityWord inDirection:UITextLayoutDirectionLeft];

    NSLog(@"Word that is currently being edited is : %@", [textView textInRange:textRange]);
}

这将为您提供当前正在输入的完整

例如,如果您输入 输入 并输入 inp ,它会为您提供 < EM> INP 即可。此外,如果您位于 中间 一词的中间位置,并将其更改为 midddle ,它将为您提供<强> midddle 即可。这里的技巧是标记化

我已将代码放在textViewDidChange:内,以便在之后输入一词进行输入/编辑。如果您希望之前最后一个字符更改(即即将更改的字词),请将代码放在textView:shouldChangeTextInRange:replacementText:中。

PS:您必须处理边缘案例,例如句子和段落被粘贴/删除。您可以通过更改粒度来修改此代码以获取字符/句子/段落等,而不仅仅是单词。查看UITextGranularity ENUM的声明以获取更多选项:

typedef NS_ENUM(NSInteger, UITextGranularity) {
    UITextGranularityCharacter,
    UITextGranularityWord,
    UITextGranularitySentence,
    UITextGranularityParagraph,
    UITextGranularityLine,
    UITextGranularityDocument
};

答案 1 :(得分:2)

您可以简单地扩展UITextView并使用以下方法返回光标当前位置周围的单词:

extension UITextView {

    func editedWord() -> String {

        let cursorPosition = selectedRange.location
        let separationCharacters = NSCharacterSet(charactersInString: " ")

        // Count how many actual characters there are before the cursor.
        // Emojis/special characters can each increase selectedRange.location
        // by 2 instead of 1

        var unitCount = 0
        var characters = 0
        while unitCount < cursorPosition {

            let char = text.startIndex.advancedBy(characters)
            let int = text.rangeOfComposedCharacterSequenceAtIndex(char)
            unitCount = Int(String(int.endIndex))!
            characters += 1
        }


        let beginRange = Range(start: text.startIndex.advancedBy(0), end: text.startIndex.advancedBy(characters))
        let endRange = Range(start: text.startIndex.advancedBy(characters), end: text.startIndex.advancedBy(text.characters.count))

        let beginPhrase = text.substringWithRange(beginRange)
        let endPhrase = text.substringWithRange(endRange)

        let beginWords = beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
        let endWords = endPhrase.componentsSeparatedByCharactersInSet(separationCharacters)

        return beginWords.last! + endWords.first!
    }
}

答案 2 :(得分:1)

UITextView委托方法:-textView:textView shouldChangeTextInRange:range replacementText:text它的行为是,它询问是否应在指定范围textView.text的文本视图中替换指定的文本。

每次在更新字符到文本视图之前键入字符时,都会调用此方法。这就是为什么当你输入range.location中的第一个字符时,textView为0的原因。

只有当此方法的返回为真时,textView才会更新我们在textView中输入的内容。

这是apple提供的-textView:textView shouldChangeTextInRange:range replacementText:text方法参数的定义:

范围: - 当前选择范围。如果范围的长度为0,则范围反映当前插入点。如果用户按下Delete键,则范围的长度为1,空字符串对象替换该单个字符 文字: - 要插入的文字。

这就是方法和您的要求的解释如下所示:

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
        //Un-commend this check below :If you want to detect the word only while new line or white space charactor input 
        //if ([text isEqualToString:@" "] || [text isEqualToString:@"\n"])
        //{
            // Getting the textView text upto the current editing location
            NSString * stringToRange = [textView.text substringWithRange:NSMakeRange(0,range.location)];

            // Appending the currently typed charactor
            stringToRange = [stringToRange stringByAppendingString:text];

            // Processing the last typed word 
            NSArray *wordArray       = [stringToRange componentsSeparatedByString:@" "];
            NSString * wordTyped     = [wordArray lastObject];

            // wordTyped will give you the last typed object
            NSLog(@"\nWordTyped :  %@",wordTyped);
        //}
        return YES;
}

答案 3 :(得分:1)

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    NSString *string = [textView.text stringByReplacingCharactersInRange:range withString:text];

    if ([text isEqualToString:@"\n"] || [text isEqualToString:@" "])
    {
        NSString *currentString = [string stringByReplacingOccurrencesOfString:@"\n" withString:@" "];

        NSLog(@"currentWord==> %@",currentString);
    }

    return YES;
}

答案 4 :(得分:0)

range委托方法中的- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text参数指向您更改UITextView字符串值的确切位置。

结构的location属性指向更改的字符串索引,这很简单。 length通常不等于text.length,请注意,用户可以从字符串中选择字符以将其替换为另一个字符串。