Sort on a string that may contain a number

前端 未结 23 2074
走了就别回头了
走了就别回头了 2020-11-22 02:59

I need to write a Java Comparator class that compares Strings, however with one twist. If the two strings it is comparing are the same at the beginning and end of the strin

23条回答
  •  旧巷少年郎
    2020-11-22 03:29

    Interesting little challenge, I enjoyed solving it.

    Here is my take at the problem:

    String[] strs =
    {
      "eee 5 ffffd jpeg2001 eee",
      "eee 123 ffffd jpeg2000 eee",
      "ffffd",
      "aaa 5 yy 6",
      "ccc 555",
      "bbb 3 ccc",
      "bbb 9 a",
      "",
      "eee 4 ffffd jpeg2001 eee",
      "ccc 11",
      "bbb 12 ccc",
      "aaa 5 yy 22",
      "aaa",
      "eee 3 ffffd jpeg2000 eee",
      "ccc 5",
    };
    
    Pattern splitter = Pattern.compile("(\\d+|\\D+)");
    
    public class InternalNumberComparator implements Comparator
    {
      public int compare(Object o1, Object o2)
      {
        // I deliberately use the Java 1.4 syntax, 
        // all this can be improved with 1.5's generics
        String s1 = (String)o1, s2 = (String)o2;
        // We split each string as runs of number/non-number strings
        ArrayList sa1 = split(s1);
        ArrayList sa2 = split(s2);
        // Nothing or different structure
        if (sa1.size() == 0 || sa1.size() != sa2.size())
        {
          // Just compare the original strings
          return s1.compareTo(s2);
        }
        int i = 0;
        String si1 = "";
        String si2 = "";
        // Compare beginning of string
        for (; i < sa1.size(); i++)
        {
          si1 = (String)sa1.get(i);
          si2 = (String)sa2.get(i);
          if (!si1.equals(si2))
            break;  // Until we find a difference
        }
        // No difference found?
        if (i == sa1.size())
          return 0; // Same strings!
    
        // Try to convert the different run of characters to number
        int val1, val2;
        try
        {
          val1 = Integer.parseInt(si1);
          val2 = Integer.parseInt(si2);
        }
        catch (NumberFormatException e)
        {
          return s1.compareTo(s2);  // Strings differ on a non-number
        }
    
        // Compare remainder of string
        for (i++; i < sa1.size(); i++)
        {
          si1 = (String)sa1.get(i);
          si2 = (String)sa2.get(i);
          if (!si1.equals(si2))
          {
            return s1.compareTo(s2);  // Strings differ
          }
        }
    
        // Here, the strings differ only on a number
        return val1 < val2 ? -1 : 1;
      }
    
      ArrayList split(String s)
      {
        ArrayList r = new ArrayList();
        Matcher matcher = splitter.matcher(s);
        while (matcher.find())
        {
          String m = matcher.group(1);
          r.add(m);
        }
        return r;
      }
    }
    
    Arrays.sort(strs, new InternalNumberComparator());
    

    This algorithm need much more testing, but it seems to behave rather nicely.

    [EDIT] I added some more comments to be clearer. I see there are much more answers than when I started to code this... But I hope I provided a good starting base and/or some ideas.

提交回复
热议问题