5

How can I capitalize the first letter of each sentence in an NSString? For example, the string: @"this is sentence 1. this is sentence 2! is this sentence 3? last sentence here." should become: @"This is sentence 1. This is sentence 2! Is this sentence 3? Last sentence here."

amirfl
  • 1,634
  • 2
  • 18
  • 34
  • u can refer http://stackoverflow.com/questions/2432452/how-to-capitalize-the-first-word-of-the-sentence-in-objective-c – Sugan S Mar 20 '13 at 04:39
  • also this http://ioshouse.com/2012/10/how-to-capitalize-first-letter-of-a-word-or-a-sentence-in-objective-c/ – Sugan S Mar 20 '13 at 04:42
  • 1
    These links address only the question of capitalizing the first letter of a single string, but not the combination of multiple strings with different separators (., !, ?). – Martin R Mar 20 '13 at 07:22

6 Answers6

3
static NSString *CapitalizeSentences(NSString *stringToProcess) {
    NSMutableString *processedString = [stringToProcess mutableCopy];


    NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en"];


    // Ironically, the tokenizer will only tokenize sentences if the first letter
    // of the sentence is capitalized...
    stringToProcess = [stringToProcess uppercaseStringWithLocale:locale];


    CFStringTokenizerRef stringTokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (__bridge CFStringRef)(stringToProcess), CFRangeMake(0, [stringToProcess length]), kCFStringTokenizerUnitSentence, (__bridge CFLocaleRef)(locale));


    while (CFStringTokenizerAdvanceToNextToken(stringTokenizer) != kCFStringTokenizerTokenNone) {
        CFRange sentenceRange = CFStringTokenizerGetCurrentTokenRange(stringTokenizer);

        if (sentenceRange.location != kCFNotFound && sentenceRange.length > 0) {
            NSRange firstLetterRange = NSMakeRange(sentenceRange.location, 1);

            NSString *uppercaseFirstLetter = [[processedString substringWithRange:firstLetterRange] uppercaseStringWithLocale:locale];

            [processedString replaceCharactersInRange:firstLetterRange withString:uppercaseFirstLetter];
        }
    }


    CFRelease(stringTokenizer);


    return processedString;
}
fumoboy007
  • 5,345
  • 4
  • 32
  • 49
1

Use

-(NSArray *)componentsSeparatedByCharactersInSet:(NSCharacterSet *)separator

put all the separator(? ,. ,! ) from which you expect beginning of new sentence, make sure to put back the actual separator and capitalize the first object in the array and then use

-(NSString *)componentsJoinedByString:(NSString *)separator

to join them back with space separator

for capitalizing the first letter of each sentence run for loop for all elements of the array.

NSString *txt = @"hello!" txt = [txt stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[txt substringToIndex:1] uppercaseString]];

Manish Agrawal
  • 10,958
  • 6
  • 44
  • 76
1

This seems to work:

NSString *s1 = @"this is sentence 1. this is sentence 2! is this sentence 3? last sentence here.";

NSMutableString *s2 = [s1 mutableCopy];
NSString *pattern = @"(^|\\.|\\?|\\!)\\s*(\\p{Letter})";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL];
[regex enumerateMatchesInString:s1 options:0 range:NSMakeRange(0, [s1 length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
    //NSLog(@"%@", result);
    NSRange r = [result rangeAtIndex:2];
    [s2 replaceCharactersInRange:r withString:[[s1 substringWithRange:r] uppercaseString]];
}];
NSLog(@"%@", s2);
// This is sentence 1. This is sentence 2! Is this sentence 3? Last sentence here.
  • "(^|\\.|\\?|\\!)" matches the start of the string or ".", "?", or "!",
  • "\\s*" matches optional white space,
  • "(\\p{Letter})" matches a letter character.

So this pattern finds the first letter of each sentence. enumerateMatchesInString enumerates all the matches and replaces the occurrence of the letter by the upper case letter.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
1

This is the solution I finally came up with. I created a category to extend NSString with the following methods:

    -(NSString *)capitalizeFirstLetter
{
    //capitalizes first letter of a NSString
    //find position of first alphanumeric charecter (compensates for if the string starts with space or other special character)
    if (self.length<1) {
        return @"";
    }
    NSRange firstLetterRange = [self rangeOfCharacterFromSet:[NSCharacterSet alphanumericCharacterSet]];
    if (firstLetterRange.location > self.length)
        return self;

    return [self stringByReplacingCharactersInRange:NSMakeRange(firstLetterRange.location,1) withString:[[self substringWithRange:NSMakeRange(firstLetterRange.location, 1)] capitalizedString]];

}

-(NSString *)capitalizeSentences
{
    NSString *inputString = [self copy];

    //capitalize the first letter of the string
    NSString *outputStr = [inputString capitalizeFirstLetter];

    //capitalize every first letter after "."
    NSArray *sentences = [outputStr componentsSeparatedByString:@"."];
    outputStr = @"";
    for (NSString *sentence in sentences){
        static int i = 0;
        if (i<sentences.count-1)
            outputStr = [outputStr stringByAppendingString:[NSString stringWithFormat:@"%@.",[sentence capitalizeFirstLetter]]];
        else
            outputStr = [outputStr stringByAppendingString:[sentence capitalizeFirstLetter]];
        i++;
    }

    //capitalize every first letter after "?"
    sentences = [outputStr componentsSeparatedByString:@"?"];
    outputStr = @"";
    for (NSString *sentence in sentences){
        static int i = 0;
        if (i<sentences.count-1)
            outputStr = [outputStr stringByAppendingString:[NSString stringWithFormat:@"%@?",[sentence capitalizeFirstLetter]]];
        else
            outputStr = [outputStr stringByAppendingString:[sentence capitalizeFirstLetter]];
        i++;
    }
    //capitalize every first letter after "!"
    sentences = [outputStr componentsSeparatedByString:@"!"];
    outputStr = @"";
    for (NSString *sentence in sentences){
        static int i = 0;
        if (i<sentences.count-1)
            outputStr = [outputStr stringByAppendingString:[NSString stringWithFormat:@"%@!",[sentence capitalizeFirstLetter]]];
        else
            outputStr = [outputStr stringByAppendingString:[sentence capitalizeFirstLetter]];
        i++;
    }

    return outputStr;
}
@end
amirfl
  • 1,634
  • 2
  • 18
  • 34
1

This solution works for me:

NSMutableString *processedString = [NSMutableString stringWithString:[stringToProcess uppercaseString]];
NSRange range = {0, [processedString length]};

[processedString enumerateSubstringsInRange:range options:NSStringEnumerationBySentences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {

    substringRange.location++;
    substringRange.length--;

    NSString *replacementString = [[processedString substringWithRange:substringRange] lowercaseString];
    [processedString replaceCharactersInRange:substringRange withString:replacementString];
}];

NB: As mentioned by fumoboy007 the string needs to be converted to upper case at the beginning otherwise enumeration does not work properly.

pheedsta
  • 2,058
  • 2
  • 16
  • 11
  • This is beautiful. However this first-uppercase-everything then -lowercase character-by-character is not too "optimal". Also, is this enumeration adhering to the current locale of the OS? I see the CFString based variation below, which is much longer and cumbersome - but is it more efficient than this one? – Motti Shneor Jun 25 '23 at 18:27
0

I wanted to do this today and came up with this for a mutable string "str" that can contain many sentences:

    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(^|\\.|\\!|\\?)\\s*[a-z]" options:0 error:NULL];
    for (NSTextCheckingResult* result in [regex matchesInString:str options:0 range:NSMakeRange(0, str.length)]) {
       NSRange rng = NSMakeRange(result.range.length+result.range.location-1, 1);
       [str replaceCharactersInRange:rng withString:[[str substringWithRange:rng] uppercaseString]];
    }

My solution required that I only try to capitalize non-accented latin letters, hence the [a-z].

Used to perl I thought this was a bit long, so I checked stack overflow. Apart from one answer that is similar, I guess we can't go simpler than this...

Ecuador
  • 1,014
  • 9
  • 26