【问题标题】:Ignoring certain strings when sorting an array对数组进行排序时忽略某些字符串
【发布时间】:2010-12-06 07:12:47
【问题描述】:

我正在制作一个语言应用程序,我有一长串与该语言相关的词汇表(德语,如果有人感兴趣的话)。我的应用程序具有在按德语单词或按英语单词排序 tableview 之间切换的功能。

当我使用以下内容时:

NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:type];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
NSArray *array = [[string componentsSeparatedByString:@"\n"] sortedArrayUsingSelector:@selector(compare:)];

它工作得非常完美——我的意思是,完全符合预期。然而,我想改进的是,有些词,如动词或名词,总是以前缀开头,如“to”,如“to do something”或“the”前面名词。所以我想做的是以某种方式将这些从我的排序中排除,因为否则我最终会在数组中的“t”部分下按字母顺序对所有动词进行排序,这对用户不是很友好。

我查看了有关 NSString 和 NSArray 的 Apple 文档,因为这是 compare 函数所在的位置(除非我非常错误),但我没有找到任何对我有意义的方法。这是我第一次做这样的数据处理,所以我可能会遗漏一些简单的东西,所以我非常感谢一些帮助。

非常感谢

Michaeljvdw

【问题讨论】:

    标签: iphone objective-c ios4 nsstring nsarray


    【解决方案1】:

    你在正确的轨道上。你想用什么来代替(内置的)compare 方法是编写你自己的方法,如果它们存在,可以消除“to”或“the”位,然后使用现有的compare 方法。

    您的电话将如下所示:

    NSArray *array = [[string componentsSeparatedByString:@"\n"] sortedArrayUsingSelector:@selector(myCompare:)];
    

    使用您通过以下方法提供给NSString 的自定义类别:

    // This method can be exposed in a header
    - (NSComparisonResult)myCompare:(NSString*)aString
    {
     NSString* selfTrimmed = [self removeArticles];
     NSString* aStringTrimmed = [s2 removeArticles];
     return [self compare:aString];
    }
    
    // This method can be kept private in the .m implementation
    - (NSString*)removeArticles
    {
        NSRange range = NSMakeRange(NSNotFound, 0);
        if ([self hasPrefix:@"to "])
        {
         range = [self rangeOfString:@"to "];
        }
        else if ([self hasPrefix:@"the "])
        {
         range = [self rangeOfString:@"the "];
        }
    
     if (range.location != NSNotFound)
     {
      return [self substringFromIndex:range.length];
     }
     else
     {
      return self;
     }
    }
    

    【讨论】:

    • +1 用于自定义比较。如果担心 "to " 或 "the " 可能出现在字符串开头之外的某个位置,您可以使用 Shaggy 的代码,但也要验证 range.location == 0 (或不太优雅的 substringWithRange isEqualToString 东西,首先检查字符串长度等)
    • @Matthew Frederick 好点。更改为使用 hasPrefix,这将确保 rangeOfString 仅在文章开头时才能找到它。
    【解决方案2】:

    您可能对localizedCompare:localizedStandardCompare: 有一些运气,但我认为这两者都不会像您想要的那样去掉冠词和介词。相反,您可能必须在 NSString 上定义一个类别,以提供您正在寻找的特定排序方式:

     @interface NSString (MySortAdditions)
     - (NSComparisonResult)compareWithoutArticles:(NSString *)other;
     @end
    
     @implementation NSString (MySortAdditions)
     - (NSComparisonResult)compareWithoutArticles:(NSString *)other {
        NSMutableString *mutableSelf = [NSMutableString stringWithString:self];
        [mutableSelf
            replaceOccurrencesOfString:@"das"
            withString:@""
            options:NSCaseInsensitiveSearch
            range:NSMakeRange(0, [mutableSelf length])
        ];
    
        ...
    
        // delete articles from 'other' too
    
        NSCharacterSet *trimSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
        NSString *trimmedSelf = [mutableSelf stringByTrimmingCharactersInSet:trimSet];
        NSString *trimmedOther = ...;
    
        return [trimmedSelf localizedCaseInsensitiveCompare:trimmedOther];
     }
     @end
    

    然后您可以使用@selector(compareWithoutArticles:) 作为NSArray 的排序选择器。

    【讨论】:

    • 这看起来很像我想要的,但是当你说 replaceOccurrencesOfString:@“das” withString@“ “ ...因为我实际上需要“das”(等)留在数组中,我只需要从排序中忽略它。这段代码是否解决了这个问题?顺便也谢谢你的回答,谢谢你的帮助。
    • 是的,该代码实际上所做的是创建正在比较的字符串的副本,然后修改它们以删除任何文章和空格。也就是说,回想起来,出于性能原因,修改字符串可能更有意义,而是使用compare:options:range:locale: 比较两个字符串的子范围。
    【解决方案3】:

    首先,不要使用compare:。请改用localizedCompare:。这很重要,因为á 是紧跟在a 之后还是在z 之后作为单独的字母出现取决于语言。 localizedCompare: 负责这一点。

    --编辑

    正如贾斯汀所说,localizedStandardCompare: 是要使用的选择器!我不知道那个方法。正如文档中所写,localizedStandardCompare:localizedCompare: 做得更多,尽管文档没有确切说明它的作用。

    --编辑结束

    如果您想要更多,您需要自己实现。为此,您可以使用 category。先声明一下

      @interface NSString (MichaelsSuperCompareCategory)
           -(NSComparisonResult)michaelsSuperCompare:(NSString*)string;
      @end
    

    然后实施

      @interface NSString (MichaelsSuperCompareCategory)
           -(NSComparisonResult)michaelsSuperCompare:(NSString*)string{
                 ...
           }
      @end
    

    通过这种方式,您可以将方法添加到现有类。然后你可以使用

    NSArray *array = [[string componentsSeparatedByString:@"\n"] 
                                     sortedArrayUsingSelector:@selector(michaelsSuperCompare:)];
    

    在方法名称前加上一些独特的前缀很重要,以免意外与 Apple 使用的内部方法崩溃。

    至于功能,据我所知,您需要自己实现。您可以使用[NSLocale currentLocale] 获取当前语言环境。您可以为您知道的语言实现更好的行为,然后默认为localizedCompare: 用于未知语言。

    【讨论】:

      【解决方案4】:

      我会以某种方式对所有数据执行-replaceOccurancesOfStrings,例如“To”->“”-然后重新加载数据。 (或者这可以在文本编辑器中)

      另一件要考虑的事情是,例如将“to walk”更改为“walk (to)”,这可以提前完成(并且在用户按字母顺序滚动时也会减少用户的混乱)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-05-02
        • 1970-01-01
        • 2022-01-02
        • 1970-01-01
        • 1970-01-01
        • 2016-07-18
        相关资源
        最近更新 更多