Как избежать разделения слова на два UITextViews

#iphone #objective-c #cocoa-touch #uitextview

#iPhone #objective-c #cocoa-touch #uitextview

Вопрос:

Я думаю, это немного неудобный вопрос, поэтому позвольте мне перефразировать его с иллюстрацией: введите описание изображения здесь

У меня есть UITextView, который ограничен определенным количеством символов. Это регулярно проверяется с помощью - (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString *)aText . Как только размер текста превышает пороговое значение удержания (на иллюстрации это было бы 8 символов), приложение переходит к следующему TextView и копирует следующий введенный символ (в данном случае p) в новый UITextView. Затем пользователь может ввести оставшуюся часть слова (в данном случае py).

Вместо разделения слова на два UITextViews, я хотел бы, чтобы в следующем UITextView было все слово ‘happy’. Другими словами, мне нужно скопировать ‘hap’ из строки 1 в начало строки 2, а затем удалить ‘hap’ из строки 1.

Я придумал этот код, который проверяет строку 1 на наличие пробелов и копирует все после пробела в строку 2. Но это не сработает:

 NSLog(@"text of current string: %@", aTextView.text);           // e.g. "I am hap"
         NSLog(@"chars in aTextView.text: %i", aTextView.text.length);  // e.g. 8 chars
         NSLog(@"text for next string: %@ ", aText);                    // e.g. "py"

         NSString *aTextModified = aText;

         for (int i = aTextView.text.length; i > 0; i--) {

             NSLog(@"I currently check: '@%'", [aTextView.text characterAtIndex:i]);

             if ([[aTextView.text characterAtIndex:i] isEqualToString:@" "]) {
                 // job done
             } else {
                 NSLog(@"I add %@ infront of %@", [aTextView.text characterAtIndex:i], aText);
                 aTextModified = [NSString stringWithFormat:@"%@%@", [aTextView.text characterAtIndex:i], aText];
                 NSLog(@"I delete %@ as I have put it into the next string...", [aTextView.text characterAtIndex:i]);
                 [aTextView.text characterAtIndex:i] = @"";
             }
         }
  

XCode выдает мне предупреждение «Недопустимый тип получателя «unichar» для строки if ([[aTextView.text characterAtIndex:i] isEqualToString:@" "]) . Полагаю, я неправильно использую characterAtIndex? Мне не разрешено применять это к тексту (который должен быть UIString) в UITextView?

Кроме того, я получаю сообщение об ошибке «Значение LValue требуется как левый вариант присвоения» для последней строки [aTextView.text characterAtIndex:i] = @""; Опять же, я думаю, я действительно не понимаю, как получить доступ к символу в UITextView и изменить его.

Я был бы очень благодарен за любые предложения о том, как сделать это правильно, и если есть более простые способы достичь того, что я пытаюсь сделать.

Комментарии:

1. что произойдет, если размер слова превышает пороговое значение?

2. @Nick Weaver: Ну, оно не может быть больше порогового значения, так как оно будет автоматически обрезано. Например. если вы попытаетесь ввести ‘areallylongword’, оно будет обрезано после ‘areallylo’, а ‘n’ будет помещено в следующую строку. Я проверяю строку после каждого введенного символа. Кроме того, мои строки 1 и 2 намного больше, чем 8 символов — я просто взял это для иллюстрации, чтобы упростить задачу. На самом деле, я смотрю на весь UITextView, заполняющий экран… Проблема заключается в проверке последнего слова, введенного на этом экране, и необходимости его переноса на следующий экран. Большое спасибо за вашу помощь

Ответ №1:

Несколько вещей

 NSLog(@"I currently check: '@%'", [aTextView.text characterAtIndex:i]);
  

Здесь вы получаете C символ, поэтому вы должны использовать %c вместо него.

 [[aTextView.text characterAtIndex:i] isEqualToString:@" "]
  

Опять же, то, что вы здесь делаете, — это отправка сообщения C символу, который неверен. Вы можете изменить его на [aTextView.text characterAtIndex:i] == " " , чтобы сделать это правильно.

 [aTextView.text characterAtIndex:i] = @"";
  

text определяется как неизменяемая строка. Вы не можете изменить это таким образом. Вам придется объявить изменяемую строку и скопировать содержимое text поверх. После внесения изменений в изменяемую строку вы можете установить для нее значение text .

Это также даст вам последнее слово.

 NSScanner *wordsScanner = [NSScanner scannerWithString:@"I am happy however I want the last word and it's positions !!!!"];
NSString *theLastWord;
while (![wordsScanner isAtEnd]) {
    [wordsScanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:amp;theLastWord];
}

// theLastWord has the value.
  

Редактировать

 NSString *text = aTextView.text;
int index = text.length - 1;
while ([text characterAtIndex:index] != " ") {
    index--;
}

NSString stringToBeMoved = [text substringFromIndex:index];
aTextView.text = [text substringToIndex:(index 1)];
  

Комментарии:

1. Большое спасибо. Я попробую и дам вам знать, как все прошло.

2. На самом деле, я немного смущен объявлением изменяемой строки и последующим копированием содержимого текста… как мне это сделать? Просто Char replacementChar = ""; а затем [aTextView.text characterAtIndex:i] = replacementChar; не сработало бы, верно?

Ответ №2:

Хорошо, давайте начнем с простого. Я создал следующее регулярное выражение, которое будет соответствовать последнему слову в строке, и если есть символы, не являющиеся словами, такие как пробелы или знаки препинания.

Я думаю, что проще работать с регулярным выражением и определять, где оно соответствует, чтобы манипулировать строкой. Однако я не уверен, какой будет производительность в больших текстах, но я думаю, что это можно решить, используя некоторые предположения, такие как: textview one не будет пропускать первые 1000 символов, поэтому может быть безопасно использовать только последние 50 символов для регулярного выражения.

 NSString *aString = @"I am happy however I want the last word and it's positions !!!!";

NSString * const regularExpression = @"\b(\w )\b(\W*)$";

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regularExpression
                                                                       options:NSRegularExpressionCaseInsensitive | NSRegularExpressionUseUnicodeWordBoundaries
                                                                         error:amp;error];

NSArray *matches = [regex matchesInString:aString
                                  options:0
                                    range:NSMakeRange(0, [aString length])];

for (NSTextCheckingResult *match in matches) {
    for (int i = 0; i < [match numberOfRanges]; i  ) {
        NSLog(@"substring %d: %@", i, [aString substringWithRange:[match rangeAtIndex:i]]);
    }
}
  

Если оно совпадает, вы можете легко выполнить итерацию по результату, который дает вам последнее слово и некоторые завершающие символы, не являющиеся словами, но самое главное, что вы получаете диапазон каждого соответствия, чтобы вы могли определить, превышен ли порог.

Комментарии:

1. Спасибо, Ник. Но я думаю, проблема в том, что я не получаю полную строку. Я получаю только символ за раз! Помните, что я использую - (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)aRange replacementText:(NSString *)aText — поэтому я получаю только текст, который обычно состоит только из одного символа. Другими словами, приложение постоянно проверяет, когда вы вводите каждый символ. Если вы попытаетесь добавить еще один символ и пересечь пороговое значение, я хочу отделить начало последнего слова, которое я пытался ввести (например, позиции, которые я больше не мог вводить). Я хочу, чтобы ‘positi’ копировался в следующий UITextView.

2. Я попытаюсь поработать в вашем коде и дам вам знать, где я застрял. Я думаю, моя самая большая проблема в том, что я не использую NSMakeRange…

3. @n.evermind ну, вы могли бы переключиться на метод делегирования textViewDidChange и просто использовать myTextField.text в качестве входных данных, чтобы проверка происходила каждый раз, когда пользователь нажимает клавишу.