如何排序字母数字字符串

时间:2014-11-27 11:10:07

标签: java sorting

我在排序包含整数的字符串时遇到问题。如果我使用下面的代码,我会得到如下排序: 1some,2some,20some,21some,3some,some

但我希望它排序如下: 1some,2some,3some,20some,21some,some

我该怎么做?

谢谢!

Collections.sort(selectedNodes,
    new Comparator<DefaultMutableTreeNode>() {
    @Override
    public int compare(DefaultMutableTreeNode o1,
        DefaultMutableTreeNode o2) {
        return o1.getUserObject().toString()
            .compareTo(o2.getUserObject().toString());
    }
    });

11 个答案:

答案 0 :(得分:7)

以下是有关如何执行此操作(未特别优化)的自包含示例:

final Pattern p = Pattern.compile("^\\d+");
String[] examples = { 
   "1some", "2some", "20some", "21some", "3some", "some", "1abc", "abc"
};
Comparator<String> c = new Comparator<String>() {
    @Override
    public int compare(String object1, String object2) {
        Matcher m = p.matcher(object1);
        Integer number1 = null;
        if (!m.find()) {
            return object1.compareTo(object2);
        }
        else {
            Integer number2 = null;
            number1 = Integer.parseInt(m.group());
            m = p.matcher(object2);
            if (!m.find()) {
                return object1.compareTo(object2);
            }
            else {
                number2 = Integer.parseInt(m.group());
                int comparison = number1.compareTo(number2);
                if (comparison != 0) {
                    return comparison;
                }
                else {
                    return object1.compareTo(object2);
                }
            }
        }
    }
};
List<String> examplesList = new ArrayList<String>(Arrays.asList(examples));
Collections.sort(examplesList, c);
System.out.println(examplesList);

<强>输出

[1abc, 1some, 2some, 3some, 20some, 21some, abc, some]

<强>解释

  • 该示例使用常量Pattern来推断某个数字是否在String的起始位置。
  • 如果第一个String中没有,则将其与第二个String进行比较。
  • 如果确实存在于第一个中,它会检查第二个。
  • 如果第二个不存在,则按原样比较两个Integer
  • 如果同时存在,则会比较String而不是整个String,因此会产生数字比较,而不是字典比较
  • 如果数字比较相同,则返回到整个{{1}}的字典比较(感谢MihaiC发现此一个)

答案 1 :(得分:3)

您的解决方案位于The Alphanum Algorithm,您可以实施this

答案 2 :(得分:3)

首先制作一个字母数字比较器,将字符串拆分为String或Integer部分。

public class AlphaNumericalComparator implements Comparator<String> {
    @Override
    public int compare(String o1, String o2) {
        List<Object> parts1 = partsOf(o1);
        List<Object> parts2 = partsOf(o2);
        while (!parts1.isEmpty() && !parts2.isEmpty()) {
            Object part1 = parts1.remove(0);
            Object part2 = parts2.remove(0);
            int cmp = 0;
            if (part1 instanceof Integer && part2 instanceof Integer) {
                cmp = Integer.compare((Integer)part1, (Integer)part2);
            } else if (part1 instanceof String && part2 instanceof String) {
                cmp = ((String) part1).compareTo((String) part2);
            } else {
                cmp = part1 instanceof String ? 1 : -1; // XXXa > XXX1
            }
            if (cmp != 0) {
                return cmp;
            }
        }
        if (parts1.isEmpty() && parts2.isEmpty()) {
            return 0;
        }
        return parts1.isEmpty() ? -1 : 1;
    }

    private List<Object> partsOf(String s) {
        List<Object> parts = new LinkedList<>();
        int pos0 = 0;
        int pos = 0;
        boolean wasDigit = false;
        while (true) {
            if (pos >= s.length()
                    || Character.isDigit(s.charAt(pos)) != wasDigit) {
                if (pos > pos0) {
                    String part = s.substring(pos0, pos);
                    parts.add(wasDigit? Integer.valueOf(part) : part);
                    pos0 = pos;
                }
                if (pos >= s.length()) {
                    break;
                }
                wasDigit = !wasDigit;
            }
            ++pos;
        }
        return parts;
    }
};

然后在你自己的比较器中使用这个比较器,在Java 8中你可以简单地使用Comparator的静态方法。

答案 3 :(得分:0)

您需要实现自己的Comparator来执行此类自定义排序。默认的String.compareTo()方法似乎在字符前对数字进行排序。将0中的20somes中的3some进行比较时,0具有更高的排序优先级,因此整个单词首先排序。
你需要做的是:尝试将字符串分成数字和字符部分。这是一项艰巨的任务,因为那些String可能包含许多这些部分(或者不是这些部分?)。您可以使用像Alphanum这样的算法,Murtaza已经向您展示了这些算法 如果您想自己实现它,可以检查数字部分的结束位置。然后使用int将其解析为Integer.parse()。比较int部分String中的{{1}}部分,然后比较其余部分。那可能不是最专业的解决方案,但作为一个初学者,你可能想要自己制作这些东西来学习它。

答案 4 :(得分:0)

您不能使用默认的String compareTo(),而是需要按照以下算法比较字符串。

  1. 按字符循环遍历第一个和第二个字符串字符并获取所有字符串或数字的块
  2. 检查块是数字还是字符串
  3. 如果数字按数字排序,则使用String compareTo()
  4. 重复这些步骤。

答案 5 :(得分:0)

您可以使用正则表达式在一行中创建它的核心来提取数字部分:

Collections.sort(selectedNodes, new Comparator<DefaultMutableTreeNode>() {
    @Override
    public int compare(DefaultMutableTreeNode o1,
        DefaultMutableTreeNode o2) {
        return Integer.parseInt(o1.getUserObject().toString().replaceAll("\\D", "")) -
            Integer.parseInt(o2.getUserObject().toString().replaceAll("\\D", ""));
    }
});

答案 6 :(得分:0)

这是Java的有效解决方案。如果您对代码有任何建议,请在我的Gist上告诉我。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class FB {

    public static int comparator(String s1, String s2) {

        String[] pt1 = s1.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))"); 
        String[] pt2 = s2.split("((?<=[a-z])(?=[0-9]))|((?<=[0-9])(?=[a-z]))"); 
//pt1 and pt2 arrays will have the string split in alphabets and numbers

        int i=0;
        if(Arrays.equals(pt1, pt2))
            return 0;
        else{
            for(i=0;i<Math.min(pt1.length, pt2.length);i++)
                if(!pt1[i].equals(pt2[i])) {
                    if(!isNumber(pt1[i],pt2[i])) {
                        if(pt1[i].compareTo(pt2[i])>0)
                            return 1;
                        else
                            return -1;
                    }
                    else {
                        int nu1 = Integer.parseInt(pt1[i]);
                        int nu2 = Integer.parseInt(pt2[i]);
                        if(nu1>nu2)
                            return 1;
                        else
                            return -1;
                    }
                }
        }

        if(pt1.length>i)
            return 1;
        else
            return -1;
    }

    private static Boolean isNumber(String n1, String n2) {
        // TODO Auto-generated method stub
        try {
            int nu1 = Integer.parseInt(n1);
            int nu2 = Integer.parseInt(n2);
            return true;
        }
        catch(Exception x) {
            return false;
        }

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        String[] examples = {"1some", "2some", "20some", "21some", "3some", "some", "1abc", "abc"};
        List<String> values = new ArrayList<String>(Arrays.asList(examples));

        System.out.println(values);
        Comparator<String> com = (o1,o2) -> {return comparator(o1,o2);}; //lambda expression

        Collections.sort(values,com);
        System.out.println(values);
    }
}

输出:

[1some, 2some, 20some, 21some, 3some, some, 1abc, abc]
[1abc, 1some, 2some, 3some, 20some, 21some, abc, some]

答案 7 :(得分:0)

如果您知道模式始终为NUMALPHA或ALPHANUM,并且alpha始终相同:

if(str1.length() != str2.length()){
   return str1.length() - str2.length();
}

return str1.compareTo(str2);

答案 8 :(得分:0)

如果您有字母数字字符串数组,则可以使用

直接对其进行排序
Arrays.sort(Array_name)

和 然后打印:

for(String a : Array_name)
    System.out.print(a);

答案 9 :(得分:0)

  

如何使用Java在Java中对字符串,字母数字和数值进行排序   比较器

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AlphaNumericSorting {
    public static void main(String[] args) {
        final Pattern p = Pattern.compile("^\\d+");
        String[] examples = { "CD", "DE", "0A", "0B", "0C", "12", "0K", "TA", "0D", "01", "02", "11", "AB", "MN" };
        Comparator<String> c = new Comparator<String>() {
            @Override
            public int compare(String object1, String object2) {
                Matcher m = p.matcher(object1);
                Integer number1 = null;
                if (!m.find()) {
                    Matcher m1 = p.matcher(object2);
                    if (m1.find()) {
                        return object2.compareTo(object1);
                    } else {
                        return object1.compareTo(object2);
                    }
                } else {
                    Integer number2 = null;
                    number1 = Integer.parseInt(m.group());
                    m = p.matcher(object2);
                    if (!m.find()) {
                        // return object1.compareTo(object2);
                        Matcher m1 = p.matcher(object1);
                        if (m1.find()) {
                            return object2.compareTo(object1);
                        } else {
                            return object1.compareTo(object2);
                        }
                    } else {
                        number2 = Integer.parseInt(m.group());
                        int comparison = number1.compareTo(number2);
                        if (comparison != 0) {
                            return comparison;
                        } else {
                            return object1.compareTo(object2);
                        }
                    }
                }
            }
        };
        List<String> examplesList = new ArrayList<String>(Arrays.asList(examples));
        Collections.sort(examplesList, c);
        System.out.println(examplesList);
    }
}

输出:-

[AB,CD,DE,MN,TA,0A,0B,0C,0D,0K,01、02、11、12 ]

答案 10 :(得分:-5)

    String [] str = new String[]{"1some", "2some", "20some", "21some", "3some", "some"};
    List<String> list = Arrays.asList(str);

    Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
    System.out.println(list);