Check valid IPv4 Address in Java - java

I am using the sun.net.util.IPAddressUtil package to check whether the string contains a valid IPv4 and IPv6 address or not.
Code Snippet is:-
String ipv4addr="200";
if(IPAddressUtil.isIPv4LiteralAddress(ipv4addr))
{
System.out.println("valid ipv4 address");
}
else
{
System.out.println("not valid");
}
But for addresses such as 200 and 300 it is still saying it is a valid IPv4 address, which it isn't.
When I used the same package and checked for IPV6 address using :-
String ipv6addr="200";
if(IPAddressUtil.isIPv6LiteralAddress(ipv6addr))
{
System.out.println("valid ipv6 address");
}
else
{
System.out.println("not valid");
}
I get the correct result. However, IPv4 does not seem to be working or may be I am using it incorrectly. Please guide me. I don't want to use regex for IPv4 validation...

There's a reason you're getting a "valid" result: 200 is a valid IPv4 address.
See, to the computer, an IPv4 address is just a 32-bit number. The dots are entirely for our convenience, because we humans suck at memorizing big precise numbers. But they don't have to be there; there are rules about how an address gets parsed depending on how many parts it has.
When an address consists of one number, it's considered a 32-bit number, and each byte is 8 bits of that number. If you were to parse "200" as an IP address, it would be equivalent to 0.0.0.200. Likewise, "2130706433" would be equivalent to 127.0.0.1.
There are also standards for when an address has two parts like 0.200 (first part is the first byte, and the second part is a 24-bit number representing the other 3 bytes), and even 0.0.200 (first two numbers are bytes, the last part is 16 bits and takes up the other 2 bytes). The "unusual" formats are leftovers from the days of IP address classes, but almost all software that has to parse addresses will understand them. (If you pop open your browser and go to http://1249739112* or even http://74.125.33128*, for example, Google's home page will come up.)
* See the comments for clickable links. Thanks, "link validator". :P
See http://download.oracle.com/javase/6/docs/api/java/net/Inet4Address.html or http://www.perlmonks.org/?node_id=221512, or http://en.wikipedia.org/wiki/IPv4#Address_representations, for some more details.
Java understands these formats as well (as does .net, as well as any decent OS), and parses the address correctly whether it contains 1, 2, 3, or 4 parts.
If you want to check that a would-be address actually looks like "xxx.xxx.xxx.xxx", then you'll probably want to explicitly check that using a pattern, or using a validation library that considers 32-bit numbers as invalid addresses (even though they are valid). I wouldn't bother, though -- if you use the lookup functions provided, you can accept an address in any standard format and it will work.
(All this mess changes with IPv6; there's a much stricter format, and you can't just type in some 36-digit number and expect it to work. But the platform still knows how to parse an address, and you should trust it to do so.)

Check out Guava's InetAddresses class which contains static utility methods for working with IP addresses. (As I understand it uses the sun.net.util.IPAddressUtil class behind the scenes.)
System.out.println(InetAddresses.isInetAddress("400")); // false

It's not a good idea to use internal "sun" packaged classes, I'd try using Apache's Validator
http://commons.apache.org/validator/
which has IP Address validation.

If you want to validate if a string is valid IP address representation, the source code of org.apache.http.conn.util.InetAddressUtils uses these regular expressions:
IPV4_PATTERN = Pattern.compile(
"^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
IPV6_STD_PATTERN = Pattern.compile(
"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
IPV6_HEX_COMPRESSED_PATTERN = Pattern.compile(
"^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");

That string is an IPv4 string format that was originally introduced by the aton_inet utility in BSD Unix and has persisted until this day in the various Unix and Linux flavours and elsewhere.
https://linux.die.net/man/3/inet_aton
The IPAddress Java library will do validation that can be configured to support aton_inet formats or not. The javadoc is available at the link. Disclaimer: I am the project manager.
Verify if an address is valid, allow inet_aton style:
String str = "200";
IPAddressString addrString = new IPAddressString(str);
try {
IPAddress addr = addrString.toAddress();
System.out.println("valid address: " + addr.toCanonicalString());
} catch(IPAddressStringException e) {
System.out.println(e.getMessage());
}
Output:
valid address: 0.0.0.200
Verify if an address is valid, do not allow inet_aton style:
IPAddressStringParameters parameters = new
IPAddressStringParameters.Builder().allow_inet_aton(false).toParams();
addrString = new IPAddressString(str, parameters);
try {
IPAddress addr = addrString.toAddress();
System.out.println("valid address: " + addr.toCanonicalString());
} catch(IPAddressStringException e) {
System.out.println(e.getMessage());
}
Output:
200 IP Address error: options do not allow IPv4 address with less than four segments

After a small research I ended up with something like this
public static boolean isValidIP4Address(String ipAddress) {
if (ipAddress.matches("^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$")) {
String[] groups = ipAddress.split("\\.");
for (int i = 0; i <= 3; i++) {
String segment = groups[i];
if (segment == null || segment.length() <= 0) {
return false;
}
int value = 0;
try {
value = Integer.parseInt(segment);
} catch (NumberFormatException e) {
return false;
}
if (value > 255) {
return false;
}
}
return true;
}
return false;
}
which was fine for simple checks.

Related

Java exception, RegEx

i'm new to java programming and i'm trying to validate an email value using RegEx, the program should throw an exception when the user provides a wrong value, i managed to do this with an if-else. However, when i try to handle the error using a try-catch block the RegEx does not work anymore and the wrong value gets displayed anyways. How can i solve this?
here's the code
try {
String emailRegex = "^(.+)#(.+).(.+)$";
if(email.matches(emailRegex)) {
Pattern pattern = Pattern.compile(emailRegex);
System.out.println(pattern.matcher(email).matches());
} else {
throw new IllegalArgumentException();
}
} catch (IllegalArgumentException ex) {
System.out.println(ex.getLocalizedMessage());
}
This regular expression rejects valid email addresses. Even if you did fix it. For example, foo#bar is actually valid (top-level domains can contain MX records. A few do!). This is the general formula for 'is it valid email':
Does it contain spaces? If yes, reject.
Does it contain at least 1 #? If no, reject.
Is the last # at position 0 (i.e. at the start), or at the end? Reject.
Otherwise, pass. There are a few invalid emails that would nevertheless pass, but this is by and large no problem: foo#bar is not really legal, but the only real way to know that, is to send an email to it and request the user click a link inside it before they can continue. No regexp is ever going to figure out if the email address entered by a user is in fact a valid email address, let alone an email address that belongs to that user, hence, there is no real point in trying to go any further than that. You're attempting to catch honest typoes, not actually validate anything, because that is impossible. Note that it can easily become legal tomorrow - someone just needs to set up the bar top level domain and make sure there's an MX record for it in its DNS registration and voila. foo#bar is now legal.
Your regex is close to this ideal; you just want ^.+#.+$
NB: If you want to break spec and reject any email addresses to top-level domains, your regex is broken. Your intent is clearly to want foo#a.b, but you don't do that - that middle ., nestled between (.+), is still a regex dot operator, meaning: "any character". You'd want \\. for that instead. But, don't - as I said, TLDs are themselves rare as mail servers, but valid according to spec!
Fix this and your code 'works', but note that your code can go only one of two ways:
The regexp matches, in which case you again run the string through the regexp (seems rather pointless to do it twice!), and then trivially prints 'true'. The entire Pattern pattern = ...; System.out.println(...) might as well be System.out.println("true"); - that's what it will always do - yes, the regexp that just matched, is still going to match, of course.
The regexp does not match, in which case we get to the else block, which throws an exception. This then goes to the catch block which can only catch this (as nothing else throws IllegalArgumentEx here), and prints the 'localized message', which is null here.
So, this code prints true if it matches, and null if it does not. That seems.. weird. And is needlessly complicated if that's what you wanted.
Better:
class Test {
private static final Pattern EMAIL_PATTERN = Pattern.compile("^.+#.+$");
public static boolean isValidEmail(String email) {
return EMAIL_PATTERN.matcher(email).matches();
}
public static void main(String[] args) {
var keyboard = new Scanner(System.in);
while (true) {
System.out.print("Enter an email address: ");
String line = keyboard.nextLine().trim();
if (line.isEmpty()) System.exit(0);
if (isValidEmail(line)) {
System.out.println("Valid");
} else {
System.out.println("Not valid");
}
}
}
}
The try/catch block do not add anything useful here. You use try/catch when you want to transfer an error condition across method calls, not within the same method call, and not when the only meaningful data you can convey is a boolean flag. If that's all you have ('valid' or 'not valid'), almost always you just want a boolean.
If you really want the exception instead:
class Test {
private static final Pattern EMAIL_PATTERN = Pattern.compile("^.+#.+$");
public static void validateEmail(String email) throws IllegalArgumentException {
if (!EMAIL_PATTERN.matcher(email).matches()) {
throw new IllegalArgumentException("Email '" + email + "' is not valid");
}
}
public static void main(String[] args) {
var keyboard = new Scanner(System.in);
while (true) {
System.out.print("Enter an email address: ");
String line = keyboard.nextLine().trim();
if (line.isEmpty()) System.exit(0);
try {
validateEmail(line);
System.out.println("Valid");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
}
}
}

libphonenumber - formatting phone numbers without knowing the country code

I have heard a lot of good from what appears to be an awesome library but I find myself in a delicate situation.
This is the first project I have ever worked where I am supposed to store phone numbers in a database.
I have read a bit about the E.164 format and I do intend to store all phone numbers using this format in my database.
The problem I am facing, is the data source. I have no control over the data source. All I known is that I am receiving a bunch of phone numbers and their format is not consistent. Some have the international extension, some don't. Some have parenthesis, hyphens, leading 0, etc. some don't.
How could I possibly extract the phone numbers from said source, format them into E.164 so that I can store them safely ?
I have tried using the PhoneNumberUtil#parse() method without providing the country code, since I don't have access to that information.
Have a look at the following example:
System.out.printLn("Number -> " + phoneNumberUtil.parse("00336555233634", null).toString())
Error type: INVALID_COUNTRY_CODE. Missing or invalid default region.
In my example, the number is that of french mobile phone. The two starting 0 works if you dial from outside France, I believe.
But the library cannot understand it as it is laking the country code.
Does that mean there does not exist a way to understand where that particular phone number is coming from ?
The documentation seems clear about it :
public PhoneNumber parse(CharSequence numberToParse, String defaultRegion)
#param defaultRegion region that we are expecting the number to be
from. This is only used if * the number being parsed is not
written in international format. The country_code for the *
number in this case would be stored as that of the default region
supplied. If the number * is guaranteed to start with a '+'
followed by the country calling code, then RegionCode.ZZ * or
null can be supplied.
So, if add the +33
System.out.printLn("Number -> " + phoneNumberUtil.parse("+336555233634", null).toString())
Then naturally the result is:
Number -> Country Code: 33 National Number: 336555233634
What should / can I do if the end-user supplies my app with phone numbers that do not start with + ? I cannot believe I am the only one if this situation.
Thanks for the help !
You need to use E164Format only. Here I took Norway as example
I have test case which tests and give the phone number in one format.
public static String getE164FormattedMobileNumber(String mobile, String locale)
throws PhoneNumberFormatException {
try {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
PhoneNumber phoneProto = phoneUtil.parse(mobile, locale);
if (phoneUtil.isValidNumber(phoneProto)
&& phoneUtil.isPossibleNumberForType(phoneProto, PhoneNumberType.MOBILE)) {
return phoneUtil.format(phoneProto, PhoneNumberFormat.E164);
}
throw new PhoneNumberFormatException(
"Mobile number is invalid with the provided locale");
} catch (NumberParseException e) {
throw new PhoneNumberFormatException("Error in parsing mobile number", e);
}
}
and the test case as follows.
// this is the test mobile used
private String expectedMobileNumber = "+4746205615";
private List<String> sucessMobileNumbers;
private List<String> failMobileNumbers;
public PhoneNumberE164FormatTest() {
sucessMobileNumbers =
Arrays.asList(
"46205615",
"004746205615",
"+4746205615",
"4746205615",
"46205615",
"+47 46205615",
"462 05 615");
failMobileNumbers = Arrays.asList("abcdsds3434", "abcdsds343?#4", "21448410", "9946739087");
}
#Test
public void e164FormattedMobileNumbersSucessCase() throws PhoneNumberFormatException {
for (String mobileNumber : sucessMobileNumbers) {
Assert.assertEquals(
expectedMobileNumber,
(PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO)));
}
}
#Test(expected = PhoneNumberFormatException.class)
public void e164FormattedMobileNumbersFailCase() throws PhoneNumberFormatException {
for (String mobileNumber : failMobileNumbers) {
PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO);
}
}
Store the original phone numbers in a non-operational column RAW_PHONE, and the canonical E.164 standardized number in you PHONE column ("00" -> "+", "(" -> "" and such). This way you are prepared for check lists and manual corrections, and improving the conversion.
Imaginable is having two phone columns in the table, and as second value just another extension -203.
Better not to fill the strict field if the conversion fails on country code or is otherwise dubious. Is the default France, or what when the user lives in Belgium?
One might argue that the source (location) of user registration determines the default country code.

Spell-Check: Find one-to-one token difference mapping between two strings

I recently stumbled over this question on an internet archive and am having some difficulty wrapping my head around it. I want to find a desired mapping amongst the different tokens between two strings. The output should a String-to-String map.
For example:
String1: hewlottpackardenterprise helped american raleways in N Y
String2: hewlett packard enterprise helped american railways in NY
Output:
hewlottpackardenterprise -> hewlett packard enterprise
hewlott -> hewlett
raleways -> railways
N Y -> NY
Note: I have been able to write an edit-distance method, which finds all types of edits (segregated by types, like deletion, substitution etc.) and can convert the first string to second by a convert method
What have I tried so far?
Approach 1: I began with a naive approach of splitting both the strings by space, inserting the tokens of the first string into a hash map and comparing the tokens of the other string with this hashmap. However, this approach quickly fails as misses on relevant mappings.
Approach 2: I utilize my covert method to find the edit positions in the string, and type of edits. Using space edits, I'm able to create a mapping from hewlottpackardenterprise -> hewlett packardenterprise. However, the method just explodes as more and more things need to be splitted within the same word.
Appreciate any thoughts in this regard! Will clear any doubts in the comments.
public String returnWhiteSpaceEdittoken(EditDone e, List<String> testTokens) {
int pos = e.pos, count=0, i=0;
String resultToken = null;
if (e.type.equals(DeleteEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count==pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
resultToken = testTokens.get(i) + " " + testTokens.get(i+1);
} else if (e.type.equals(InsertEdit)) {
for (i=0;i<testTokens.size();i++) {
count+=testTokens.get(i).length();
if (count>pos) {
break;
}
if (i!=testTokens.size()-1) {
count++;
}
}
String token = testTokens.get(i);
resultToken = token.substring(count-token.length(), pos) + token.substring(pos, count);
}
return resultToken;
}
A pretty common way of handling problems like this is to find the longest common subsequence (or it's dual the shortest edit script) between the two strings and then post-process the output to get the specific format you want; in your case the string maps.
Wikipedia has a pretty decent introduction to the problem here: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
and a great paper "An O(ND) Difference Algorithm and Its Variations" by Myers can be found here. http://www.xmailserver.org/diff2.pdf

Get IP and execute on IF statement

I can't process with my code.
I want to start my application if local Internet Protocol is equal to "XXX"
What i have wrote already wrote
Code:
InetAddress IP=InetAddress.getLocalHost();
System.out.println("SYSTEM IP = "+IP.getHostAddress());
Console :
SYSTEM IP= 192.168.0.69
How can i check: if my Internet Protocol is equal to 192.168.0.69 (or any i will get on other PC)
code executes;
else:
stops?
Thanks for advice if any!
getHostAddress returns a String:
public String getHostAddress()
↑
So simply do:
if("192.168.0.69".equals(IP.getHostAddress())) {
//...
}
It's preferable not to use magic strings, so make it static final String..
if(IP.getHostAddress().equals("192.168.0.69")){
//code executes
}else{
// stops
}
if(IP != null && IP.getHostAddress().equals("192.168.0.69"))
{
System.out.println("The address is matched");
}
IP.getHostAddress() method return the value in `String` so you can check the IP address using `equals` method.

what is the best way to parse this string in java?

what is the best way to parse this string in java ?
Admin State State Type Interface Name
-------------------------------------------------------------------------
Enabled Connected Dedicated Local Area Connection
Enabled Connected Dedicated Local Area Connection 2
between each word is space, not tab, not any thing else, as you can see number of space is not equal, and also between the word such as "local area connection" is space.
actually i want the name of all of my network interface and the state of them.
this is the output of "netsh" command in windows. (if you know other command witch can get me this info as key:value, it will be helpfull. or may be there is a argument for this command to format it?)
if i can get something like this it will help alot :
Interface Name : Local Area Connection
Type : Dedicated
State : Connected
Admin State : Enabled
Interface Name : Local Area Connection 2
Type : Dedicated
State : Connected
Admin State : Enabled
BufferedReader b = new BufferedReader(new StringReader(myString));
String line;
while (!(line = b.readLine()).startsWith("-----")) {/*skip*/};
while ((line = b.readLine()) != null) {
if (line.trim().equals("")) continue; // skip blank lines
String[] splat = line.split(" +",4);
System.out.println("Interface Name : " + splat[3]);
System.out.println("Type : " + splat[2]);
System.out.println("State : " + splat[1]);
System.out.println("Admin State : " + splat[0]);
}
b.close();
You should use Java capabilities to get the network interfaces. The class NetworkInterface provides what you are looking for.
You can find an example here: Listing Network Interface Addresses
If the columns are of known width, use String.substring(..) to get each column & trim() the result.
If there's no column separator:
1 - It seems to be fixed size fields. This means the columns will always have X caracters, and next column will always start at X+1. In your exemple, "Admin State" will always have 15 characters and "State" will always begin on 16th character. "State" has also 15 characters [...]
2 - If fixed size fields don't work, you can try to parse by 2 spaces, but its way prone to errors
If you know the positions, you can do like
String state = line.substring(15, 30).trim();
If you don't know, then parse the first line for the known headers (like line.indexOf("State")), that will tell you the positions.
// for the header line
int stateBegin = line.indexOf("State");
int typeBegin = line.indexOf("Type");
// for all other lines
String state = line.substring(stateBegin, typeBegin).trim();
String s ="Admin State State Type Interface Name";
String[] str = s.split(" +");
for(String ss: str)
System.out.println(ss);
Try above code to split String with more than one space.
Output:
Admin State
State
Type
Interface Name

Categories

Resources