I need to write a regex for PIN validation.
The PIN is 4-digits and must not consist of contiguous numbers.
Examples of contiguous numbers:
[ 1111, 1234, 9876, 8888, 0987, 0123 ]
I tried this link, but it only checks for identical digits, not contiguous ones.
Could you suggest working regex for me?
The regex only match
That is why a regex like (adjusted to 4 digits):
^(\\d)(?!\\1+$)\\d{3}$
, showed in link "this" (link found question) will only check for identical digits.
Note: The original expression is made a bit smaller, so it will be easier to follow - without the quantifiers. In expression '(?<!\1)\d', "\1 -> group(1)" matches “\d -> a didgit” that is not preceded by “group(1)”, using negative lookbehind. It doesn’t match an equal digit.
We would like to have arithmetic operators directly in the regex, applying it on "group(1)", in order to solve it with only regex, but that is not supported by regex.
Here is an alternative, not regex though, first the core code snippet:
int digit = Integer.parseInt(String.valueOf(pin.charAt(i)));
int nextDigit = Integer.parseInt(String.valueOf(pin.charAt(i + 1)));
if (digit >= nextDigit - 1 && digit <= nextDigit + 1) {
resultMap.put(pin, false);
break;
}
Code snippet in context and "testbench":
public static void main(String[] args) {
List<String> inputs =
Arrays.asList("1111", "1234", "9876"
, "8888", "0987", "0123"
, "1358", "0268", "9635");
Map<String, Boolean> resultMap = new LinkedHashMap<>();
for (String pin : inputs) {
for (int i = 0; i < pin.length() - 1; i++) {
resultMap.put(pin, true);
int digit = Integer.parseInt(String.valueOf(pin.charAt(i)));
int nextDigit = Integer.parseInt(String.valueOf(pin.charAt(i + 1)));
if (digit >= nextDigit - 1 && digit <= nextDigit + 1) {
resultMap.put(pin, false);
break;
}
}
}
System.out.println(resultMap);
}
Output:
{1111=false, 1234=false, 9876=false, 8888=false, 0987=false, 0123=false, 1358=true, 0268=true, 9635=true}
Related
The following question was asked in my last interview (yesterday), and I'm trying to solve it since then (couldn't solve it in the interview).
Sorry for any grammar mistakes or any logical mistakes, I don't have the question, it was written by memory:
You are given a number in a string format, for example: "14438832066".
You got to sum up the consecutive equal digits in that number. If no
consecutive equal digit was found, just add the digit to the result.
for example: solution(19938832066) => 11831632012
Explanation: first digit is 1.
The second and third digits are both 9 which means they will turn into 18 in the result string.
So on
with the rest of the digits (as you can see, the last 2 digits are both 6 which means they will turn into 12 in the result string).
You are required to do that for the result string as well, if needed, until no equal consecutive digits are found in the number.
Example:: number: 14438832066 solution( "19938832066") ->"11831632012" -> "2831632012"
Explanation: first result is 11831632012, but then you can see that there are still equal consecutive digits : the first and the
second digits are both 1. So process that number as well.
You are given a string and must return a string.
My solution:
I couldn't write the solution, I don't know why. It's a pretty simple question, I thought going recursive at first but didn't want to complex things.
I wrote 2 helper methods:
one that returns a boolean whether the number consists of equal consecutive digits.
one that actually makes the business logic:
turn the string into a char array
create a counter that will count instances of the same digit - (int counter = 1).
loop on the array from the first to the one before the last element :
inside the loop:
//equal digit was found - increment counter and continue to next digit
if char[i] == char[i+1] then counter++
//calculation in case we are done counting the same digit
else if counter > 0 then result.append(counter*digit[i])
// if no consecutive equal digit was found
else result.append(digit[i])
end loop: return result
Problems I had:
I created the counter inside the loop, so each iteration it got rested. took me few minutes to realize.
I had troubles realizing that 'int(digit[i])' doesn't give me the numeric value of the char, it gives the ASCII value. I had to use "Character.getNumericValue" (don't remember the exact name of the method).
Because of these problems, it took me 45 minutes to write the solution which in the end didn't even work.
I'll be glad to get a working solution, and even better - to get any feedback and tips on my solution and what, in your opinion, were my mistakes.
Thank you.
Your pseudo-code seems alright, as far as it goes. What's missing is that you don't repeatedly check the result string to see if another pass is required. I also show how you don't need to remember the API to convert a character to a digit; if you know the digits are decimal, you can interpret them yourself. As an interviewer, I would accept that there is an API that you can't precisely remember or your home-brew solution as equally valid.
String transform(String number) {
while (true) {
String result = collapse(number);
if (result.equals(number)) return result;
number = result;
}
}
private static String collapse(String number) {
StringBuilder result = new StringBuilder();
for (idx = 0; idx < number.length(); ) {
int mark = idx;
int digit = digitAt(number, idx++);
while (idx < number.length() && digitAt(number, idx) == digit) ++idx;
result.append((idx - mark) * digit);
}
return result.toString();
}
private static int digitAt(String num, int index) {
char ch = number.charAt(index);
if (ch < '0' || ch > '9') throw new IllegalArgumentException();
return ch - '0';
}
The preceding is a naïve approach that transforms the string until there are no changes. I suspect there might be a more "elegant" approach that works from left to right through the input in a single pass, but it would take some thought, and I probably couldn't come up with that in an interview.
Here's an algorithm that uses recursion and a for-loop to add consecutive equal digits. I think the code is pretty self-explanatory but please ask if you have any queries.
public static String addConsecutiveDigits(String number) {
char[] arr = number.toCharArray();
StringBuilder result = new StringBuilder();
boolean foundConsecutive = false; // boolean flag for checking if the number contained consecutive equal digits
for (int i = 0; i < arr.length; i++) {
int digit = arr[i] - '0'; //Subtracting ascii values to get integer values
int newNumber = digit;
if (i != arr.length - 1) {
int nextDigit = arr[i + 1] - '0';
if (digit == nextDigit) { // check if the digits are consecutive digits
newNumber = digit + nextDigit;
i++; // increment i as we have already added the i+1 digit
foundConsecutive = true;
}
}
result.append(newNumber);
}
if (!foundConsecutive) // if no consecutive equal digits were found then return the result;
return result.toString();
else // recurse to check for more consecutive equal digits
return addConsecutiveDigits(result.toString());
}
I'm not a Java guy, so this code might not be ideal but I would do something like this:
public String solve(String input)
{
String result = "";
int i = 0;
while (i < input.length())
{
var first = input.charAt(i);
if (i == input.length() - 1){
result += first;
break;
}
var second = input.charAt(i + 1);
if (first == second){
result += (Character.getNumericValue(first) + Character.getNumericValue(second));
i += 2;
} else {
result += first;
i += 1;
}
}
return result;
}
For the second part, I would just run the function in a loop until the result matches the input.
I want to take in a string for example "1234567890" and add commas to each thousands place in the number. However, I don't want to parse this string into an int or long. I think I might need to use recursion but I dont know how.
String number1 = "1234567890";
System.out.println(stringNumberAddCommas(number1));
//output == 1,234,567,890
public static String stringNumberAddCommas(String number1){ }
we can achieve this as below as well-
public static String stringNumberAddCommas(String number) {
for (int i = number.length() - 1; i >= 0; ) {
if (i >= 3) {
number = number.substring(0, i - 2) + "," + number.substring(i - 2);
}
i = i - 3;
}
System.out.println("number=" + number);
return number;
}
There's no need to mess with recursion; all you need is to realize that you need to either work backwards or do some very basic math based on length.
Given a pile o digits that is, say, 8 characters long, that's all the information you need to know that the first comma is after 2 digits, and then every further comma at +3 digits from that position until you reach the end.
Tools needed:
"12345678".length() (= 8)
"12345678".substring(2, 5) (= "345")
a for (int i = ...; i < in.length(); i+= 3) loop.
a new StringBuilder() along with its .append() method, both for appending the comma as well as those substrings.
Some exceedingly basic math on that length, involving in particular the % operator. a % b divides a by b, tosses the result in the garbage, and returns the leftovers. In other words, 5 % 3 returns 2 (because 5 divides into 3 one time, and that leaves a remainder of 2).
String test = "1234567890";
String reversed = new StringBuffer(test).reverse().toString();
int i = 0;
StringBuilder ans = new StringBuilder();
while(i+3<reversed.length()){
ans.append(reversed, i, i + 3).append(",");
i+=3;
}
ans.append(reversed, i, reversed.length());
String solution = ans.reverse().toString();
I'd define an offset to find the length of the first substring, then iterate over the string in 3 character substrings.
StringJoiner would also be helpful in adding the needed commas.
public static String stringNumberAddCommas(String str){
int offset = str.length() % 3 != 0 ? str.length() % 3 : 3;
StringJoiner sj = new StringJoiner(",");
for (int s = 0, i = offset; i <= str.length(); s = i, i += 3) {
sj.add(str.substring(s, i));
}
return sj.toString();
}
Given a string, I want to extract the numbers and keep a spacing between them.
The procedure for this generally involves removing all spacing so that 12 3 becomes 123 which I'm avoiding.
For example if the input is 17/(2 + 3)-13 I want 17 2 3 13.
I also have methods that extract the operators and parenthesis in between them but I can't separate the numbers greater than 9.
Here's my attempt which produces out of bounds exceptions
public static void partition(){
String word = "123 -asdfqwerty- 45";
String kajigger = "";
for(int i = 0; i < word.length(); i++){
char c = word.charAt(i);
if(Character.isDigit(c)){
int j = i;
while(Character.isDigit(word.charAt(j))){
kajigger += word.charAt(j);
j++;
}
}
}
System.out.println(kajigger);
}
In this example I wanted the output 123 45
The general idea is converting from infix to postfix by moving all numbers the the left and operators to the right.
You go by this way :
replace all multiple following (+) chars which are non-digits (\D) by a single space (" ")
so \D+ changes 7/(2 + 3)-13 into 7 2 3 13
String str = "17/(2 + 3)-13";
str = str.replaceAll("\\D+", " ");
System.out.println(str); // 17 2 3 13
Regex demo
public int countYZ(String str) {
int count = 0;
for(int i = 0;i<str.length();i++)
if((str.charAt(i)=='y'||str.charAt(i)=='z')&&!(Character.isLetter(i+1)))
count++;
return count;
}
This code is failing the test for this criteria : Given a string, count the number of words ending in 'y' or 'z' -- so the 'y' in "heavy" and the 'z' in "fez" count, but not the 'y' in "yellow" (not case sensitive). We'll say that a y or z is at the end of a word if there is not an alphabetic letter immediately following it. (Note: Character.isLetter(char) tests if a char is an alphabetic letter.)
I tracked it by hand and cannot seem to figure out why it isn't working for many of the tests. For example, in "day fyyyz" it outputs 5 but it should be returning 2. Appreciate the help!
Two things to consider:
As pointed out by UnholySheep, Character.isLetter(i+1) isn't checking the i+1th character in the string. You'd need to use:
Character.isLetter(str.charAt(i+1))
But simply changing that can yield an IndexOutOfBoundsException, because you overrun the end of the string if the string ends with a y or z. So, change the second bit of the condition to
!(i+1 != str.length() && Character.isLetter(str.charAt(i+1)))
This also counts the y or z at the end of the string.
Of course, this can be written as:
i+1 == str.length() || !Character.isLetter(str.charAt(i+1))
which is a bit less awkward.
Overall condition:
if((str.charAt(i) == 'y' || str.charAt(i) == 'z')
&& (i+1 == str.length() || !Character.isLetter(str.charAt(i+1)))
If you want to make it case insensitive, use Character.toLowerCase(str.charAt(i)) before comparing to y and z.
Your function is return the total number of y and z characters in the string instead of the number of words ending in y or z. \\W is a regular expression token to target any non-word character in a string.
public int countYZ(String str) {
String[] words = str.split("\\W");
int tally = 0;
for (String w : words)
tally += (w.endsWith("y") || w.endsWith("z")) ? 1 : 0;
return tally;
}
This is a problem easy to solve with a regex:
String str = "day fyyyz provaz provy drad";
Matcher matcher = Pattern.compile("(?i)\\b\\w+[zy]\\b").matcher(str);
int i = 0;
while (matcher.find()) {
System.out.println(matcher.group());
i++;
}
System.out.println("found " + i);
This code will output:
day
fyyyz
provaz
provy
found 4
This regex (?i)\\b\\w+[zy]\\b means:
(?i) enable match case insensitive
\b match word boundary
\w+ match one or more word character (equal to [a-zA-Z0-9_])
[zy] Match a single character present in the list below [zy]
\b match word boundary
https://regex101.com/r/tLMobI/1
Hello everyone I was having some issue splitting up a user input number using printf (I do have to use printf). My problem is that when I put in say the number 12345 it will print the integers on five separate lines, and also has them in the reverse order. So it would look something like this when I put in the integer 12345:
5
4
3
2
1
But without the spaces (I need those as well). I want it to print like this: 1 2 3 4 5.
Here is the code I have so far:
public static void main(String[]args){
Scanner input = new Scanner(System.in);
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
while (one > 0){
System.out.printf("%d%n", one % 10);
one = one /10;
}
}
First, in order to avoid printing on separate lines, you should avoid using the %n formatting character in your printf().
Now, how do you print the digits in the correct order? Well, since you are limited to five-digit numbers, you can do something like this:
for ( int divisor = 10000; divisor >= 1; divisor /= 10 ) {
System.out.printf( "%d ", n / divisor);
n %= divisor;
}
System.out.printf( "%n" ); // Just to complete the line
(divisor /= 10 is shortcut for divisor = divisor / 10, and n %= divisor is shortcut for n = n % divisor).
So you start by dividing the number by 10000. This will give you the fifth digit from the right. Then you take the remainder and put it in n. This gives you just the remaining four digits. Then the loop will reduce your divisor to 1000, which will take the fourth digit from the right, and you keep doing that until you reach a divisor of 1.
Another approach that does not require knowing that the number is 5 digits long, but requires recursion is to write a method like so:
public static void printSplitNumber( int n ) {
if ( n == 0 ) {
return;
}
printSplitNumber( n / 10 );
System.out.printf( "%d ", n % 10);
}
And from your main, call:
printSplitNumber(n);
System.out.printf("%n"); // Again, just completing the line.
This recursive method relies on the fact that you print the current digit only after all the rest of the number has been printed. So this causes it to print it to the right of the rest of the digits, giving you the effect you need.
Unless the assignment is to figure out how to split the digits numerically, I think that the simplest approach is to either use Scanner's nextLine() method to get a String, or convert your int to a String, and then split the characters of the String.
substring() is a little heavy - a lighter-weight way to do it is by inspecting character positions, like this:
public void printDigits(String chars) {
for(int i = 0; i < chars.length(); i++) {
System.out.printf("%c ", chars.charAt(i));
}
}
This approach uses the substring method as opposed to mathematically manipulating the int value.
int one;
System.out.print("Enter the five digit integer you would like to be split up:");
one = input.nextInt();
String x = Integer.toString(one);
for(int i = 0; i < x.length() - 1; i++)
{
// On last digit in number
if(i + 1 == x.length())
{
System.out.printf("%s ", x.substring(x.length()));
}
else
{
System.out.printf("%s ", x.substring(i, i + 1));
}
}
Simplified printf statemnts thanks to #Jerry101's comment