【问题标题】:How to randomize letters correctly from an NSString如何从 NSString 中正确随机化字母
【发布时间】:2014-04-15 10:58:51
【问题描述】:

我正在创建一个单词扰码器,但在随机化字母时遇到了问题。当字母被随机化时,就没有意义了。

例如,单词 PARK 显示为 AAPA。因此,正如您所知道的,当需要解读时,它对用户没有意义。

请注意,我使用 .plist 文件来保存单词。

这是我用来随机化字母的代码:

    _words = [NSMutableArray arrayWithCapacity:scramblelength];

    for (int i=0;i<scramblelength;i++) { 

    NSString *letter = [scramble substringWithRange:[scramble rangeOfComposedCharacterSequenceAtIndex:arc4random()%[scramble length]]];

然后,我正在创建 UIImageViews 来显示乱码:

    if (![letter isEqualToString:@""]) {
        GameView *boxes = [[GameView alloc] initWithLetter:letter andSideLength:boxSide];
        boxes.center = CGPointMake(xOffset + i*(boxSide + kTileMargin), kScreenHeight/4*3);

        [self.scrambleView addSubview:boxes];
        [_words addObject:boxes];

我在这里做错了什么?我希望打乱单词中的字母有意义。

请帮忙,我被这个卡住了!

谢谢!

【问题讨论】:

  • 检查这个link。可能会有所帮助
  • 如何获得NSString 变量“scramble”?

标签: ios objective-c random nsstring scramble


【解决方案1】:

当你得到一个随机字母时,你需要做一些事情来从你的 NSMutableArray 中删除那个字母(即单词的字母按顺序排列)。因此,当您遍历单词时,每次剩余的字符都会减少。现在,从您有限的代码块(第一个)来看,您可能没有这样做。您需要类似 "[_words removeObjectAtIndex:letterIndex]" 的内容,并且您还希望在从数组中删除项目时从字母数迭代到零:for (int i=[_words count]; i > [_words count ]; i--) 因为你需要从 4 个字母减少到 0 个字母。

【讨论】:

    【解决方案2】:

    所以,我确信有更有效的方法可以做到这一点,但我遵循的原则是在你需要之前不进行优化。考虑到这一点,这段代码似乎可以正常工作:

    - (NSString *)scrambleWord:(NSString *)word {
        NSMutableArray *letterArray     = [self letterArrayFromWord:word];
        NSMutableString *returnValue    = [[NSMutableString alloc] init];
        do {
            int randomIndex = arc4random() % letterArray.count;
            [returnValue appendString:letterArray[randomIndex]];
            [letterArray removeObjectAtIndex:randomIndex];
            if (letterArray.count == 1) {
                [returnValue appendString:letterArray[0]];
                break;
            }
        } while (YES);
        if ([[returnValue copy] isEqualToString:word]) {
            return [self scrambleWord:word];
    
        } else {
            return [returnValue copy];
    
        }
    }
    - (NSMutableArray *)letterArrayFromWord:(NSString *)word {
        NSMutableArray *array = [NSMutableArray array];
        for (int i = 0; i < word.length; i = i + 1) {
            [array addObject:[NSString stringWithFormat:@"%C", [word characterAtIndex:i]]];
        }
        return array;
    }
    

    【讨论】:

    • 您需要修改您的letterArrayFromWord 方法以像原始代码一样处理组合字符;但除此之外,正如你所说,它应该可以工作,如果有点不理想的话。
    【解决方案3】:

    只要您的字符串长度适合 32 位,这应该没问题。如果没有,我会用 C++ 中的统一随机数生成器替换 arc4random_uniform,并将其编译为 Objective-C++ 模块。

    代码简单地遍历字符串,并将每个组合字符序列与来自同一字符串的一些随机组合字符序列交换。

    抱歉,当你傲慢只输入代码时就会发生这种情况。如果您对这个有问题,请告诉我...

    对于更大的字符串,有一种更有效的方法,但这似乎可以解决问题。

    NSMutableString 类别...

    @interface NSMutableString (Scramble)
    - (void)scramble;
    @end
    
    @implementation NSMutableString (Scramble)
    static void
    swapRanges(NSMutableString *string, NSRange iRange, NSRange jRange)
    {
        // Need to replace the "trailing" component first
        if (NSEqualRanges(iRange, jRange)) return;
        if (iRange.location > jRange.location) {
            NSRange tmpRange = iRange;
            iRange = jRange;
            jRange = tmpRange;
        }
        NSString *iString = [self substringWithRange:iRange];
        NSString *jString = [self substringWithRange:jRange];
        [string replaceCharactersInRange:jRange withString:iString];
        [string replaceCharactersInRange:iRange withString:jString];
    }
    
    - (void)scramble
    {
        for (NSUInteger i = 0; i < self.length; ++i) {
            NSRange iRange = [self rangeOfComposedCharacterSequenceAtIndex:i];
            NSUInteger j = arc4random_uniform(self.length);
            NSRange jRange = [self rangeOfComposedCharacterSequenceAtIndex:j];
            swapRanges(self, iRange, jRange);
        }
    }
    @end
    

    NSString 类别...

    @interface NSString (Scramble)
    - (NSString*)scrambledString;
    @end
    @implementation NSString (Scramble)
    - (NSString *)scrambledString
    {
        NSMutableString *result = [self mutableCopy];
        [result scramble];
        return [result copy];
    }
    @end
    

    示例使用...

    [someMutableString scramble];
    
    NSString *mixedUp = [someString scrambledString];
    

    或者,如果您对 C++ 感到满意,请将其转换为 std::wstring,调用 std::random_shuffle,然后将其转换为 NSString。使用经过验证的、经过良好测试的代码时,错误会减少很多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-29
      • 2014-01-07
      • 2018-07-22
      • 1970-01-01
      • 2017-11-05
      • 1970-01-01
      • 2020-12-11
      相关资源
      最近更新 更多