1

I have read on this site inlcuding: link1 and link2 amongst others how to sort IP addresses (String representation of them) in Java. However I am not getting the correct output.

My Data (an example):

::2:3:4:5:6:7

::2:3:4:5:6:7:8

1::8

1::2:3

1::2:3:4

1::5:256.2.3.4

1::3000.30.30.30

fe80::217:f2ff:254.7.237.98,1:2:3:4::5:1.2.3.4

2001:0000:1234:0000:0000:C1C0:ABCD:0876

I am adding these IP addresses (some valid some invalid) to an ArrayList and then passing it to this below:

ArrayList <String> list = new ArrayList<String>();

String [] tests = {"::2:3:4:5:6:7","2:3:4:5:6:7","::5:3:4:5:6:7:8","::5:3:4:5:6:7:8:9:0","1::8","1::2:3","1::2:3:4","1::5:256.2.3.4","1:1:3000.30.30.30","ae80::217:f2ff:254.7.237.98,1:2:3:4::5:1.2.3.4","2001:0000:1234:0000:0000:C1C0:ABCD:0876",
     "12345::6:7:8","1::1.2.900.4","fe80::","::ffff:0:0"};

//Add to ArrayList

    for (String test1 : tests) {
    list.add(test1);
    }

//Compare and sort

 Collections.sort(list);
    Collections.reverse(list);

    //Collections.sort(ipList, new Comparator<String>() {
    for(String ip: list){
    System.out.println(ip);
}

However I am not able to correctly sort the data and get incorrectly sorted results in DESCENDING ORDER. Can anyone guide me to a better way ? Thanks in advance. Please remember in ip addresses between "::" there is a zero so this is equivalent to 0:0:0

The result I get is:

fe80::

ae80::217:f2ff:254.7.237.98,1:2:3:4::5:1.2.3.4

::ffff:0:0

::5:3:4:5:6:7:8:9:0

::5:3:4:5:6:7:8

::2:3:4:5:6:7

2:3:4:5:6:7

2001:0000:1234:0000:0000:C1C0:ABCD:0876

1::8

1::5:256.2.3.4

1::2:3:4

1::2:3

1::1.2.900.4

1:1:3000.30.30.30

12345::6:7:8

Community
  • 1
  • 1
Afshin Ghazi
  • 2,784
  • 4
  • 23
  • 37
  • 2
    You're not sorting "ip addresses". You're sorting **STRINGS** that happen to contain human-readable versions of IPs. If you want to sort them in proper numerical order, they have to get PARSED into an internal numeric format, and then those number versions get sorted. – Marc B Nov 30 '15 at 18:51
  • Use a custom Comparator. – StackFlowed Nov 30 '15 at 18:54
  • Yes I realize that. However when you PARSE (I sense some anger lol) 0:0:4 is bigger than 1:1:0 which is not what I want. Thanks for the guidance anyway. – Afshin Ghazi Nov 30 '15 at 19:10
  • Each number in an IP represents a byte worth of data (8 bits... values 0 to 255 or 0 to FF if you prefer hex). 0.0.4 becomes a value of 4. 1.1.0 becomes 1*256*256+1*256+0 = 65792 which is clearly bigger than 4. I think you are parsing wrong if you are not getting this result. Perhaps if you post your parse code we can help with that. IPV6 is the same sort of thing but each number is 16 bits, with values 0 to 65535 and 8 sets of them instead of 4, colons vs dots, etc. Point is, under it all, they are large numbers, not strings and need to be compared numerically. – LawfulEvil Nov 30 '15 at 19:32
  • Have you checked this particular SO thread: http://stackoverflow.com/questions/13756235/how-to-sort-ip-address-in-ascending-order – DevilsHnd - 退職した Nov 30 '15 at 21:01

2 Answers2

1

Try this

Test.java

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        ArrayList <String> list = new ArrayList<String>();
        String [] tests = {"::2:3:4:5:6:7","2:3:4:5:6:7","::5:3:4:5:6:7:8","::5:3:4:5:6:7:8:9:0","1::8","1::2:3","1::2:3:4","1::5:256.2.3.4","1:1:3000.30.30.30","ae80::217:f2ff:254.7.237.98","1:2:3:4::5:1.2.3.4","2001:0000:1234:0000:0000:C1C0:ABCD:0876","12345::6:7:8","1::1.2.900.4","fe80::","::ffff:0:0"};
        for (String test1 : tests)
        {
            list.add(test1);
        }

        System.out.println();
        System.out.println("Ascending Order");

        Collections.sort(list, new AlphanumComparator());
        for(String ip: list)
        {
            System.out.println(ip);
        }

        System.out.println();
        System.out.println("Descending Order");

        Collections.reverse(list);
        for(String ip: list)
        {
            System.out.println(ip);
        }
    }
}

AlphanumComparator.java

import java.util.Comparator;

public class AlphanumComparator implements Comparator
{
    private final boolean isDigit(char ch)
    {
        return ch >= 48 && ch <= 57;
    }

    private final String getChunk(String s, int slength, int marker)
    {
        StringBuilder chunk = new StringBuilder();
        char c = s.charAt(marker);
        chunk.append(c);
        marker++;
        if (isDigit(c))
        {
            while (marker < slength)
            {
                c = s.charAt(marker);
                if (!isDigit(c))
                    break;
                chunk.append(c);
                marker++;
            }
        } else
        {
            while (marker < slength)
            {
                c = s.charAt(marker);
                if (isDigit(c))
                    break;
                chunk.append(c);
                marker++;
            }
        }
        return chunk.toString();
    }

    public int compare(Object o1, Object o2)
    {
        if (!(o1 instanceof String) || !(o2 instanceof String))
        {
            return 0;
        }
        String s1 = (String)o1;
        String s2 = (String)o2;

        int thisMarker = 0;
        int thatMarker = 0;
        int s1Length = s1.length();
        int s2Length = s2.length();

        while (thisMarker < s1Length && thatMarker < s2Length)
        {
            String thisChunk = getChunk(s1, s1Length, thisMarker);
            thisMarker += thisChunk.length();

            String thatChunk = getChunk(s2, s2Length, thatMarker);
            thatMarker += thatChunk.length();

            int result = 0;
            if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))
            {
                int thisChunkLength = thisChunk.length();
                result = thisChunkLength - thatChunk.length();
                if (result == 0)
                {
                    for (int i = 0; i < thisChunkLength; i++)
                    {
                        result = thisChunk.charAt(i) - thatChunk.charAt(i);
                        if (result != 0)
                        {
                            return result;
                        }
                    }
                }
            } else
            {
                result = thisChunk.compareTo(thatChunk);
            }

            if (result != 0)
                return result;
        }

        return s1Length - s2Length;
    }
}

This gives you the order. I hope that helps

Ordered IPs

Dan
  • 7,286
  • 6
  • 49
  • 114
0

Try this.

static String normalizeIP(String s) {
    try {
        byte[] b = InetAddress.getByName(s).getAddress();
        StringBuilder sb = new StringBuilder();
        for (byte e : b)
            sb.append(String.format("%03d", Byte.toUnsignedInt(e)));
        return sb.toString();
    } catch (UnknownHostException e) {
        return s;
    }
}

public static void main(String[] args) {
    String[] ads = {
        "::2:3:4:5:6:7",
        "::2:3:4:5:6:7:8",
        "1::8",
        "1::2:3",
        "1::2:3:4",
        "1::5:255.2.3.4",
        "fe80::217:f2ff:254.7.237.98",
        "1:2:3:4::5:1.2.3.4",
        "2001:0000:1234:0000:0000:C1C0:ABCD:0876",};
    Arrays.sort(ads, (a, b) -> normalizeIP(b).compareTo(normalizeIP(a)));
    for (String s : ads)
        System.out.println(s);
}