
Java Regex on HackerRank asks you to write one regular expression that accepts valid IPv4-style addresses and rejects everything else. It looks like a one-liner, and in the end it is, but getting there teaches you the most useful regex skill: describing a range of numbers (here 0 to 255) using only characters, because regex has no idea what a number is.
The same pattern shows up in real work when you validate form input or parse log files. And in interviews, "write a regex for an IP address" is a common follow-up when you mention regex on your resume, so it pays to understand each part instead of copying it.
Problem
Create a class named MyRegex (not public) with a String field called pattern. The pattern must match a string only if it is an IP address of the form A.B.C.D, where:
- each of A, B, C and D is a number from 0 to 255,
- each part has at most 3 characters,
- leading zeros are allowed, so
000and034are fine.
By these rules, 000.12.12.034 and 121.234.12.12 are valid, while 666.666.23.23 (parts above 255), 23.45.22.32. (trailing dot), 000.12.234.23.23 (five parts) and I.Am.not.an.ip are not.
Input: several lines, each one a string made of any ASCII characters. The locked code reads them one token at a time.
Output: for each string, the locked code prints true if it matches your pattern, else false.
Input:
000.12.12.034
121.234.12.12
23.45.12.56
00.12.123.123123.123
122.23
Hello.IP
Output:
true
true
true
false
false
false
Approach
Break the job into two parts: first write a pattern for one number from 0 to 255 (call it an octet), then join four of them with dots.
Step 1: one octet. Regex sees characters, not values, so split the range into groups that are easy to describe:
[01]?\d?\dcovers 0 to 199. It is one to three digits, and if there are three, the first is 0 or 1. This also allows leading zeros like0,00,034and199.2[0-4]\dcovers 200 to 249.25[0-5]covers 250 to 255.
Put them together with alternation: ([01]?\d?\d|2[0-4]\d|25[0-5]). Nothing above 255 can match, and nothing longer than 3 characters can match.
Step 2: four octets. Join them with \.. The backslash matters. A plain . in regex means "any character", so without the backslash 1a2b3c4 passes as an IP address.
Step 3: whole string only. The locked code calls String.matches(), which only returns true if the entire string matches. So you do not need ^ and $ here. If you ever use Matcher.find() instead, add them. Without anchors, find() says yes to 9999.1.1.1, because it finds 99.1.1.1 sitting inside it (I checked this).
Dry run: 000.12.12.034 splits as 000 (first branch, starts with 0), 12, 12 and 034 (first branch again), so it is true. 122.23 has only two parts, so the four-part pattern cannot match: false. 00.12.123.123123.123 fails because 123123 has six digits and there are five parts.
Solution in Java
import java.util.Scanner;
class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
String ip = in.next();
System.out.println(ip.matches(new MyRegex().pattern));
}
in.close();
}
}
// Must NOT be public (only one public class per file on HackerRank)
class MyRegex {
// One octet: 0-199 (with optional leading zeros), 200-249, or 250-255
private static final String OCTET = "([01]?\\d?\\d|2[0-4]\\d|25[0-5])";
// Four octets joined by literal dots
public String pattern = OCTET + "\\." + OCTET + "\\." + OCTET + "\\." + OCTET;
}
In Java source code every regex backslash is written twice, so \d becomes "\\d" and \. becomes "\\.". Building the pattern from an OCTET constant keeps it readable. The older solution on this page used (...\\.){3} plus a trailing \\b. It was correct too (I compared both against 300,000 random strings and they agreed every time), the \\b just did nothing useful because matches() already checks the full string.
Besides the sample, I tested 255.255.255.255 (true), 256.1.1.1 (false), 1.2.3.4. (false), 0000.1.1.1 (false, four characters) and 1.2.3.04 (true).
Output
true
true
true
false
false
false
Complexity
Time: O(L) per input string of length L. The pattern is fixed and small, so backtracking stays bounded.
Space: O(1) extra. One small tip for real code: String.matches() compiles the pattern every time it is called. If you check thousands of strings, compile once with Pattern.compile and reuse it.
Common mistakes
- Writing
.instead of\\., which lets any character act as the separator. - Using
\d{1,3}for each part. That accepts 999 and 666, which are not valid. - Putting
25[0-5]and2[0-4]\dlogic wrong, for example2[0-5]\d, which lets 256 to 259 through. - Making the class
public. HackerRank already has a publicSolutionclass in the same file, and Java allows only one.
Next in the series: Java Regex 2 - Duplicate Words. Before that, see Pattern Syntax Checker.
Tip: try to solve the problem yourself before reading the solution. Use the code as a reference to check your approach, and make sure you understand why it works.
More HackerRank solutions All coding problems MCQ practice
See everything in one place: Coding Problems and Solutions
May i know the explanation of this program
ReplyDelete