Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort ip address in ascending order

Is there any method to sort this? Or do I just need to split it and use a loop to compare? Input

123.4.245.23
104.244.253.29
1.198.3.93
32.183.93.40
104.30.244.2
104.244.4.1

Output

1.198.3.93
32.183.93.40
104.30.244.2
104.244.4.1
104.244.253.29
123.4.245.23

So far I use HashMap to stored my data. I want sort the value by the Ip address in ascending order. Seems TreeMap is better choice?

like image 422
John Avatar asked Dec 07 '12 02:12

John


2 Answers

TLDR

You may jump directly to an efficient comparison method (See Edit section below) OR
continue your reading.


In order to sort IPs you first need to know a bit about them. There are two types of IPs; 32 Bit and 128 Bit.

32 Bit Source

32 Bit

  • The 32 bit IP is split into 4 groups of numbers between 0 and 255. These groups are seperated via a .
  • A single group, as shown above, is 8 bits of data. This is the reason the numbers in a group are limited between 0 and 255.
  • For a 32 bit IP to be formatted correctly it should be int.int.int.int. Even if the int is a 0 it must be shown in the IP address. This is different to a 128 bit IP which may omit 0s. For example ::5: which is the same as 0:0:5:0:0:0:0:0.

128 Bit Source

128 Bit

  • The 128 bit IP is split into 8 groups of numbers between 0 and FFFF (which is equivalent to 65535). Unlike a 32 bit IPs group, these groups are separated buy a :.
  • A single group, as show above, is 16 bits of data. This is the reason the numbers in the groups are limited between 0 and FFFF.
  • To format a 128 bit IP properly there are several rules you have to follow. 0s may be omitted from groups and if the remaining groups all are 0 then the groups may also be omitted. The groups have to be separated by a :. If you are omitting groups the last group which isn't a 0 has to be followed by a :. These rules leave us with a format int:int:int:int:int:int:int:int. An example of 0s and groups being omitted would be 58f:::fff:2:. This is the same as 58f:0:0:fff:2:0:0:0.

Sorting

Once the IPs have been sorted into their respective groups they can be sorted. To sort an IP you need to use a method called weighting. This is because simply adding or multiplying different groups together wouldn't work. For example take the these two IPs; 192.5.48.198 and 198.48.5.192. If you add or multiply the values of the groups together you get the same answer. So there is no way to accurately compare them using addition and multiplication. If you use weighting you get something like this.

32 Bit Weighting

Value of IP = (Group one value * 256^4) + (Group two value * 256^3) +
              (Group three value * 256^2) + (Group four value * 256)

128 Bit Weighting

Value of IP = (Group one value * 65536^8) + (Group two value * 65536^7) +
              (Group three value * 65536^6) + (Group four value * 65536^5) +
              (Group five value * 65536^4) + (Group six value * 65536^3) +
              (Group seven value * 65536^2) + (Group eight value * 65536)

The Code in Java

As long as the IP is formatted reasonably correctly this code will separate the two kinds of IP and then sort them.

import java.util.*;
import java.math.*; //For BigInteger
import java.util.regex.*;
import java.lang.*;

public class IPSort
{
    String[] tests = {":8:","::::5:6::8","::::5:6::7","::::5:6::8","123..245.23","1...","..1.","123...23",".1..","123..245.23", "123..245.23", "104.244.253.29", "1.198.3.93", "32.183.93.40", "32.183.93.40", "104.30.244.2", "104.244.4.1","0.0.0.1",":a:","::5:3:4:5:6:78","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"};
    ArrayList<String> bit32 = new ArrayList<String>();
    ArrayList<String> bit128 = new ArrayList<String>();
    ArrayList<String> cleanBit32 = new ArrayList<String>();
    ArrayList<String> cleanBit128 = new ArrayList<String>();

    boolean myMatcher32Bit(String s)
    {
        Pattern patter32Bit = Pattern.compile("^(?=(?:[^.]*\\.){3}[^.]*$)(?=(?:[^:]*:){0}[^:]*$)(?=(?:[^a-zA-Z]*[^a-zA-Z])*$)");
        Matcher matcher32Bit = patter32Bit.matcher(s);
        return matcher32Bit.find();
    }

    boolean myMatcher128Bit(String s)
    {
        Pattern patter128Bit = Pattern.compile("^(?=(?:[^.]*\\.){0}[^.]*$)(?=(?:[^:]*:){1,7}[^:]*$)");
        Matcher matcher128Bit = patter128Bit.matcher(s);
        return matcher128Bit.find();
    }

    public void sortIntoRespectiveIPTypes()
    {
        for(String s: tests)
        {
            if(myMatcher32Bit(s))
            {
                bit32.add(s);
            }
            else if(myMatcher128Bit(s))
            {
                bit128.add(s);
            }
        }

        System.out.println("32 bit IPs");
        for(String ip: bit32)
        {
            System.out.println("  "+ip);
        }

        System.out.println("\n128 bit IPs");
        for(String ip: bit128)
        {
            System.out.println("  "+ip);
        }

        int count = 0;
        for(String ip: tests)
        {
            if(myMatcher32Bit(ip)==false && myMatcher128Bit(ip)==false)
            {
                count++;
            }
        }

        if(count != 0)
        {
            System.out.println("\nDidn't match an IP format");
            for(String ip: tests)
            {
                if(myMatcher32Bit(ip)==false && myMatcher128Bit(ip)==false)
                {
                    System.out.println("  "+ip);
                }
            }
        }

    }

    public void sort32BitIPs(ArrayList<String> bit32, ArrayList<String> newBit32)
    {
        ArrayList<BigInteger> bigInt32Bit = new ArrayList<BigInteger>();
        for(String ip:bit32)
        {
            String[] tempArray = ip.split("\\.");
            int i=0;
            for(String s:tempArray)
            {
                if(s.equals(""))
                {
                    tempArray[i]="0";
                }
                i++;
            }
            bigInt32Bit.add(convert32Bit(tempArray));
        }

        Collections.sort(bigInt32Bit);

        ArrayList<String> fixFormat = new ArrayList<String>();
        for(String ip:bit32)
        {
            String[] fixArray = ip.split("\\.");
            int i=0;
            for(String s:fixArray)
            {
                if(s.equals(""))
                {
                    fixArray[i]="0";
                }
                i++;
            }

            StringBuilder strBuilder = new StringBuilder();
            for(int i2 = 0; i2 < 4; i2++) 
            {
                if(i2<3)
                {
                    try
                    {
                        if(!fixArray[i2].equals(""))
                        {
                            strBuilder.append(fixArray[i2]+".");
                        }
                        else
                        {
                            strBuilder.append(".");
                        }
                    }
                    catch(Exception e)
                    {
                        strBuilder.append("0.");
                    }
                }
                else
                {
                    try
                    {
                        strBuilder.append(fixArray[i2]);
                    }
                    catch(Exception e)
                    {
                        strBuilder.append("0");
                    }
                }
            }
            String newString = strBuilder.toString();
            fixFormat.add(newString);
            bit32=fixFormat;
        }

        for(BigInteger finalValue:bigInt32Bit)
        {
            for(String ip:bit32)
            {
                String[] tempArray = ip.split("\\.");
                int i=0;
                for(String s:tempArray)
                {
                    if(s.equals(""))
                    {
                        tempArray[i]="0";
                    }
                    i++;
                }
                if(finalValue.equals(convert32Bit(tempArray)))
                {
                    if(!newBit32.contains(ip))
                    {
                        String str = bit32.toString();
                        String findStr = ip;
                        int lastIndex = 0;
                        int count = 0;

                        while(lastIndex != -1){

                            lastIndex = str.indexOf(findStr,lastIndex);

                            if(lastIndex != -1){
                                count++;
                                lastIndex += findStr.length();
                            }
                        }

                        for(int k = 0; k<count;k++)
                        {
                            newBit32.add(ip);
                        }
                    }
                }
            }
        }
    }

    BigInteger convert32Bit(String[] array)
    {
        int[] tempArray = new int[array.length];
        ArrayList<BigInteger> tempBigIntList = new ArrayList<BigInteger>();
        int i = 0;
        for(String s:array)
        {
            int power = 4-i;
            tempArray[i]= Integer.parseInt(s);
            String string = Integer.toString(tempArray[i]);
            BigInteger myBigInt = new BigInteger(string);
            BigInteger num2 = myBigInt.multiply(new BigInteger("256").pow(power));
            tempBigIntList.add(num2);
            i++;
        }
        BigInteger bigInt32Bit = new BigInteger("0");
        for(BigInteger bI:tempBigIntList)
        {
            bigInt32Bit = bigInt32Bit.add(bI);
        }
        return bigInt32Bit;
    }

    public void sort128BitIPs(ArrayList<String> bit128,ArrayList<String> newBit128)
    {
        ArrayList<BigInteger> bigInt128Bit = new ArrayList<BigInteger>();
        for(String ip:bit128)
        {
            String[] tempArray = ip.split(":");
            int i=0;
            for(String s:tempArray)
            {
                if(s.equals(""))
                {
                    tempArray[i]="0";
                }
                i++;
            }
            bigInt128Bit.add(convert128Bit(tempArray));
        }

        Collections.sort(bigInt128Bit);

        for(BigInteger finalValue:bigInt128Bit)
        {
            for(String ip:bit128)
            {
                String[] tempArray = ip.split(":");
                int i=0;
                for(String s:tempArray)
                {
                    if(s.equals(""))
                    {
                        tempArray[i]="0";
                    }
                    i++;
                }
                if(finalValue.equals(convert128Bit(tempArray)))
                {
                    if(!newBit128.contains(ip))
                    {
                        String str = bit128.toString();
                        String findStr = ip;
                        int lastIndex = 0;
                        int count = 0;

                        while(lastIndex != -1){

                            lastIndex = str.indexOf(findStr,lastIndex);

                            if(lastIndex != -1){
                                count++;
                                lastIndex += findStr.length();
                            }
                        }

                        for(int k = 0; k<count;k++)
                        {
                            newBit128.add(ip);
                        }
                    }
                }
            }
        }
    }

    BigInteger convert128Bit(String[] array)
    {
        int[] tempArray = new int[array.length];
        ArrayList<BigInteger> tempBigIntList = new ArrayList<BigInteger>();
        int i = 0;
        for(String s:array)
        {
            int power = 8-i;
            tempArray[i]= Integer.parseInt(s,16);
            String string = Integer.toString(tempArray[i]);
            BigInteger myBigInt = new BigInteger(string);
            BigInteger num2 = myBigInt.multiply(new BigInteger("65536").pow(power));
            tempBigIntList.add(num2);
            i++;
        }
        BigInteger bigInt128Bit = new BigInteger("0");
        for(BigInteger bI:tempBigIntList)
        {
            bigInt128Bit = bigInt128Bit.add(bI);
        }
        return bigInt128Bit;
    }

    public void printInOrder(ArrayList<String> bit32,ArrayList<String> bit128)
    {
        System.out.println("\nSorted IPs");

        System.out.println("Sorted 32 bit IPs - Ascending");
        for(String ip: bit32)
        {
            System.out.println("  "+ip);
        }

        Collections.reverse(bit32);
        System.out.println("\nSorted 32 bit IPs - Descending");
        for(String ip: bit32)
        {
            System.out.println("  "+ip);
        }

        System.out.println("\nSorted 128 bit IPs - Ascending");
        for(String ip: bit128)
        {
            System.out.println("  "+ip);
        }

        Collections.reverse(bit128);
        System.out.println("\nSorted 128 bit IPs - Descending");
        for(String ip: bit128)
        {
            System.out.println("  "+ip);
        }
    }

    public void run(ArrayList<String> bit32,ArrayList<String> bit128,ArrayList<String> newBit32,ArrayList<String> newBit128)
    {
        sortIntoRespectiveIPTypes();
        sort32BitIPs(bit32,newBit32);
        sort128BitIPs(bit128,newBit128);
        printInOrder(newBit32,newBit128);
    }

    public static void main(String[] args)
    {
        IPSort ipS = new IPSort();
        ipS.run(ipS.bit32,ipS.bit128,ipS.cleanBit32,ipS.cleanBit128);
    }
}

As a note it is possible to use this class to sort IPs but my code does not use it

This code also sorts the list into an ascending order, then into a descending order. This is printed out in the command console when the code is run

Output

Output

Edit

A more efficient and accurate way to do it is with the InetAddress class mentioned above. Credits to 200_success for code.

import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Stream;

public class IPSort {
    private static String[] TESTS = {"0:0:0:0:0:0:fff:ffff","::FFFF:222.1.41.90",":8:","::::5:6::8","::::5:6::7","::::5:6::8","123..245.23","1...","..1.","123...23",".1..","123..245.23", "123..245.23", "104.244.253.29", "1.198.3.93", "32.183.93.40", "32.183.93.40", "104.30.244.2", "104.244.4.1","0.0.0.1",":a:","::5:3:4:5:6:78","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","::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"};

    public static class InetAddressComparator implements Comparator<InetAddress> {
        @Override
        public int compare(InetAddress a, InetAddress b) {
            byte[] aOctets = a.getAddress(),
                   bOctets = b.getAddress();
            int len = Math.max(aOctets.length, bOctets.length);
            for (int i = 0; i < len; i++) {
                byte aOctet = (i >= len - aOctets.length) ?
                    aOctets[i - (len - aOctets.length)] : 0;
                byte bOctet = (i >= len - bOctets.length) ?
                    bOctets[i - (len - bOctets.length)] : 0;
                if (aOctet != bOctet) return (0xff & aOctet) - (0xff & bOctet);
            }
            return 0;
        }
    }

    public static Optional<InetAddress> toInetAddress(String s) {
        try {
            return Optional.of(InetAddress.getByName(s));
        } catch (UnknownHostException badAddress) {
            return Optional.empty();
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println("Valid 32-bit addresses");
        Arrays.stream(TESTS)
              .map(IPSort::toInetAddress)
              .filter(Optional::isPresent)
              .map(Optional::get)
              .filter((addr) -> addr instanceof Inet4Address)
              .map(InetAddress::getHostAddress)
              .forEach(System.out::println);

        System.out.println("\nValid 128-bit addresses");
        Arrays.stream(TESTS)
              .map(IPSort::toInetAddress)
              .filter(Optional::isPresent)
              .map(Optional::get)
              .filter((addr) -> addr instanceof Inet6Address)
              .map(InetAddress::getHostAddress)
              .forEach(System.out::println);

        System.out.println("\nInvalid addresses");
        Arrays.stream(TESTS)
              .filter((s) -> !toInetAddress(s).isPresent())
              .forEach(System.out::println);

        System.out.println("\nSorted addresses");
        Arrays.stream(TESTS)
              .map(IPSort::toInetAddress)
              .filter(Optional::isPresent)
              .map(Optional::get)
              .sorted(new InetAddressComparator())
              .map(InetAddress::getHostAddress)
              .forEach(System.out::println);
    }
}
like image 197
Dan Avatar answered Sep 18 '22 06:09

Dan


For the ip4 adresses you showed you just need to split it up. then i would convert it to a long value, and sort by that.

long value = f3 + f2*256 + f1 * 256^2 + f0 * 256^3

where f0 - f3 are the splitted values.

like image 45
AlexWien Avatar answered Sep 22 '22 06:09

AlexWien