【问题标题】:Extract word substring from NSString at given index从给定索引处的 NSString 中提取单词子字符串
【发布时间】:2013-03-13 16:35:11
【问题描述】:

我想从给定索引处的 NSString 中提取一个子字符串。示例:

NSString = @"Hello, welcome to the jungle";
int index = 9;

索引点 '9' 位于单词 'welcome' 的中间,我希望能够将单词 'welcome' 提取为子字符串。谁能告诉我如何实现这一目标?使用正则表达式?

【问题讨论】:

  • 你想要'e'还是'welcome'?
  • 我想要“欢迎”这个词
  • 这个问题不是无效的吗?为什么有人会去寻找正则表达式或nsset?使用 nsstring 类的方法可以很容易地找到它。

标签: ios cocoa nsstring substring


【解决方案1】:

这是一个解决方案,作为 NSString 上的一个类别:

- (NSString *) wordAtIndex:(NSInteger) index {
    __block NSString *result = nil;
    [self enumerateSubstringsInRange:NSMakeRange(0, self.length)
                             options:NSStringEnumerationByWords
                          usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                              if (NSLocationInRange(index, enclosingRange)) {
                                  result = substring;
                                  *stop = YES;
                              }
                          }];
    return result;
}

还有一个更复杂的,但可以让你准确地指定你想要的单词字符:

- (NSString *) wordAtIndex:(NSInteger) index {
    if (index < 0 || index >= self.length)
        [NSException raise:NSInvalidArgumentException
                    format:@"Index out of range"];

    // This definition considers all punctuation as word characters, but you
    // can define the set exactly how you like
    NSCharacterSet *wordCharacterSet =
    [[NSCharacterSet whitespaceAndNewlineCharacterSet] invertedSet];

    // 1. If [self characterAtIndex:index] is not a word character, find
    // the previous word. If there is no previous word, find the next word.
    // If there are no words at all, return nil.
    NSInteger adjustedIndex = index;
    while (adjustedIndex < self.length &&
           ![wordCharacterSet characterIsMember:
            [self characterAtIndex:adjustedIndex]])
        ++adjustedIndex;
    if (adjustedIndex == self.length) {
        do
            --adjustedIndex;
        while (adjustedIndex >= 0 &&
               ![wordCharacterSet characterIsMember:
                [self characterAtIndex:adjustedIndex]]);
        if (adjustedIndex == -1)
            return nil;
    }

    // 2. Starting at adjustedIndex which is a word character, find the
    // beginning and end of the word
    NSInteger beforeBeginning = adjustedIndex;
    while (beforeBeginning >= 0 &&
           [wordCharacterSet characterIsMember:
            [self characterAtIndex:beforeBeginning]])
        --beforeBeginning;

    NSInteger afterEnd = adjustedIndex;
    while (afterEnd < self.length &&
           [wordCharacterSet characterIsMember:
            [self characterAtIndex:afterEnd]])
        ++afterEnd;

    NSRange range = NSMakeRange(beforeBeginning + 1,
                                afterEnd - beforeBeginning - 1);
    return [self substringWithRange:range];
}

假设单词很短,第二个版本对于长字符串也更有效。

【讨论】:

  • 所以这很好,谢谢,虽然如果索引位于单词的结尾/开头,我猜它返回 null 因为它不在范围内。有什么办法可以稍微适应这种情况吗?
  • 抱歉,它确实有效——我的错。但是,如果单词以 # 或 @ 开头,它不会注册 @ 或 # - 它们是否因为 NSStringEnumerationByWords 而丢失?
  • 我进行了一次编辑,将NSLocationInRange(index, substringRange) 更改为NSLocationInRange(index, enclosingRange),即使您落在单词边界上,它也应该会返回一个单词。我会看看 @ 或 # 的情况——你能给我一个例子,告诉我你想要什么输出吗?
  • 我正在尝试从“Hello #name how are you”中输出#name,但我只得到“name”……这有意义吗?
  • 我发布了另一个版本。如果您不希望将句点逗号、引号等视为单词字符,则可能需要对其进行调整。有趣的运动。
【解决方案2】:

这是一种相当老套的方法,但它会起作用:

NSString 有一个方法:

- (NSArray *)componentsSeparatedByString:(NSString *)separator;

所以你可以这样做:

NSString *myString = @"Blah blah blah";
NSString *output = @"";
int index = 9;
NSArray* myArray = [myString componentsSeparatedByString:@" "]; // <-- note the space in the parenthesis

for(NSString *str in myArray) {
    if(index > [str length]) index -= [str length] + 1; // don't forget the space that *was* there
    else output = str;
}

【讨论】:

  • 我很懒...我会把它留给比我更有耐心的人。
  • 不错 :) 喜欢你的幽默感
  • 使用-componentsSeparatedByString:-componentsSeparatedByCharactersInSet: 是一个不错的主意,但这段代码不起作用。对于您自己的索引为 9 的示例,它返回“Blah”而不是“blah”。对于 OP 的示例,“Hello”中的索引返回“welcome”,所有其他索引返回“Hello”。
  • @noa,你完全正确!!显然我在想什么和我的手指在做什么是完全不同的。我不小心翻转了“>”运算符哈哈。我现在没有mac,但我会在早上测试它。不过老实说,我更喜欢你的解决方案......它可以轻轻地挤入代码库中,只需最少的更改并且不会中断逻辑流:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2023-03-24
  • 2012-01-05
  • 2023-04-03
  • 2022-12-18
  • 2012-11-05
相关资源
最近更新 更多