【问题标题】:Change sort order of strings includes with a special character (e.g. "_")更改字符串的排序顺序包括带有特殊字符(例如“_”)
【发布时间】:2014-06-15 05:48:57
【问题描述】:

PHP 脚本按降序输出电子邮件地址列表,如下所示:

_abc_@testmail.com
_abc45_@testmail.com
_abc2_@testmail.com
ypaux2aux@yahoo.com
yaremchuk56@testmail.com
vasillevn@hotmail.com
ugur@hotmail.com
twes@gmail.com
tukaux@yahoo.com
ttsetaux1@yahoo.com
tra@testmail.com

在 Java 中,我从这些电子邮件中创建一个 ArrayList,然后按降序排序。结果不一样:

ypaux2aux@yahoo.com
yaremchuk56@testmail.com
vasillevn@hotmail.com
ugur@hotmail.com
twes@gmail.com
tukaux@yahoo.com
ttsetaux1@yahoo.com
tra@testmail.com
_abc45_@testmail.com
_abc2_@testmail.com
_abc_@testmail.com

差异是由下划线“_”引起的。我想实现与 PHP 脚本相同的排序顺序。我怎样才能做到这一点?我无法访问 PHP 代码。

我使用的Java测试代码是:

import java.util.ArrayList;
import java.util.Collections;

public class sorty {

    public static void main(String[] args) {
        ArrayList<String> listStrings = new ArrayList<>();

        listStrings.add("_abc_@testmail.com");
        listStrings.add("_abc45_@testmail.com");
        listStrings.add("_abc2_@testmail.com");
        listStrings.add("ypaux2aux@yahoo.com");
        listStrings.add("yaremchuk56@testmail.com");
        listStrings.add("vasillevn@hotmail.com");
        listStrings.add("ugur@hotmail.com");
        listStrings.add("twes@gmail.com");
        listStrings.add("tukaux@yahoo.com");
        listStrings.add("ttsetaux1@yahoo.com");
        listStrings.add("tra@testmail.com");

        for (int i = 0; i < listStrings.size(); i++) {

            System.out.println(listStrings.get(i));

        }

        Collections.sort(listStrings);
        Collections.reverse(listStrings);

        for (int i = 0; i < listStrings.size(); i++) {

            System.out.println(listStrings.get(i));

        }
        ;

    }

}

【问题讨论】:

    标签: java php sorting collections


    【解决方案1】:

    我会使用适当的Collator。实现自己的比较器不是 最琐碎的事情。如果您对其中一种默认设置感到满意,那最好不过了。例如

    Collections.sort(listStrings, Collator.getInstance(Locale.US));
    

    或类似的。

    如果现有的都不适合你,那么使用rule based collator 会 您的意图更清晰,然后实施比较器 imo:

    String rules = "< a < b < c < '_'" //etc
    Collections.sort(listStrings, new RuleBasedCollator(rules));
    

    【讨论】:

    • Locale.* 不适合我的示例。正如你所说,我可能需要使用 RuleBasedCollat​​or。谢谢@monocell
    【解决方案2】:

    使用理解下划线特殊的自定义比较器进行排序:

    Collections.sort(listStrings, new Comparator<String>() {
    
        @Override
        public int compare(String o1, String o2) {
            if (o1.startsWith("_") && o2.startsWith("_")) {
                return compare(o1.substring(1), o2.substring(1));
            }
    
            if (o1.startsWith("_")) {
                return 1;
            }
            if (o2.startsWith("_")) {
                return -1;
            }
    
            return o1.compareTo(o2);
        }
    });
    

    这也将处理存在多个下划线的情况。例如。 __foo 将在_foo 之后考虑。


    要处理任意数量的特殊字符,请将它们定义在一个数组中(按照您的首选顺序)并使用更高级的比较器:

    Collections.sort(listStrings, new Comparator<String>() {
    
        // declare in order of desired sort
        private final String[] specialChars = { "_", ">" };
    
        @Override
        public int compare(String o1, String o2) {
            /*
             * CASES
             * 
             * 1. Both start with same special char
             * 
             * 2. Both start with a special char
             * 
             * 3. One starts with a special char
             * 
             * 4. None starts with a special char
             */
    
            int o1SpecialIndex = -1;
            int o2SpecialIndex = -1;
    
            for (int i = 0; i < specialChars.length; i++) {
                if (o1.startsWith(specialChars[i])) {
                    o1SpecialIndex = i;
                }
                if (o2.startsWith(specialChars[i])) {
                    o2SpecialIndex = i;
                }
            }
    
            // case 1:
            if (o1SpecialIndex != -1 && o1SpecialIndex == o2SpecialIndex) {
                return compare(o1.substring(1), o2.substring(1));
            }
    
            // case 2:
            if (o1SpecialIndex != -1 && o2SpecialIndex != -1) {
                return o2SpecialIndex - o1SpecialIndex;
            }
    
            // case 3:
            if (o1SpecialIndex != -1) {
                return 1;
            }
            if (o2SpecialIndex != -1) {
                return -1;
            }
    
            // case 4:
            return o1.compareTo(o2);
        }
    });
    

    【讨论】:

    • 谢谢@Duncan;是否可以将其用于所有特殊字符,例如-&lt;。此外,有时下划线位于字符串的中间。
    • 谢谢@Duncan。如果字符串以特殊字符开头,则此方法有效。其他情况下不起作用。
    • @Turcia 啊,我明白了。如果特殊字符也出现在字符串中,你需要保持相同的顺序吗?
    • 是的,没错。我忘了添加一些有问题的示例电子邮件,例如some_thing@mail.com
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    相关资源
    最近更新 更多