validate a user input - java

Hello I'm new to programming and I'm having a trouble understanding my assignment. I know that this might be a really simple problem for you guys and I'm sorry for that. Is it possible that she's just asking me to write a method that will perform the given instructions?
Write a program to find if the user input is valid base on the instructions.**
a string must have at least nine characters
a string consists of letters and numbers only.
a string must contain at least two digits.

You can simply use the regex, ^(?=(?:\D*\d){2})[a-zA-Z\d]{9,}$ which can be explained as follows:
^ : asserts position at start of a line
Positive Lookahead (?=(?:\D*\d){2})
Non-capturing group (?:\D*\d){2}
{2} matches the previous token exactly 2 times
\D matches any character that's not a digit (equivalent to [^0-9])
* matches the previous token between zero or more time (greedy)
\d matches a digit (equivalent to [0-9])
The pattern, [a-zA-Z\d]{9,} :
{9,} matches the previous token between 9+ times (greedy)
a-z matches a single character in a-z
A-Z matches a single character in A-Z
\d matches a digit (equivalent to [0-9])
$ : asserts position at the end of a line
Demo:
import java.util.stream.Stream;
public class Main {
public static void main(String args[]) {
//Test
Stream.of(
"helloworld",
"hello",
"hello12world",
"12helloworld",
"helloworld12",
"123456789",
"hello1234",
"1234hello",
"12345hello",
"hello12345"
).forEach(s -> System.out.println(s + " => " + isValid(s)));
}
static boolean isValid(String s) {
return s.matches("^(?=(?:\\D*\\d){2})[a-zA-Z\\d]{9,}$");
}
}
Output:
helloworld => false
hello => false
hello12world => true
12helloworld => true
helloworld12 => true
123456789 => true
hello1234 => true
1234hello => true
12345hello => true
hello12345 => true

Requirement #1: a string must have at least nine characters
This is solved by checking whether the length of the String is greater than 9, with s.length()>9
Requirement #2: a string consists of letters and numbers (whole numbers) only.
Use the regex [a-zA-Z0-9]+, which matches all Latin alphabet characters and numbers.
Requirement #3: a string must contain at least two digits.
I've written a method that loops through every character and uses Character.isDigit() to check whether it is a digit.
Check it out:
public static boolean verify(String s) {
final String regex = "[a-zA-Z0-9]+";
System.out.println(numOfDigits(s));
return s.length() > 9 && s.matches(regex) && numOfDigits(s) > 2;
}
public static int numOfDigits(String s) {
int a = 0;
int b = s.length();
for (int i = 0; i < b; i++) {
a += (Character.isDigit(s.charAt(i)) ? 1 : 0);
}
return a;
}

Related

Regular Expression to check alphanumeric with decimals but reject only alphanumeric, alphabet or numeric

Need help in forming regular expression to match text's having pure decimals or alphanumeric decimals but ignoring texts with the only alphanumeric without a decimal or only numeric value or only alphabets.
I tried this ^[a-zA-Z0-9]*[0-9.]*[0-9]$ but it is accepting even alphanumeric values.
Below are the test results which I am expecting.
Text
Result
Test
false
Test1
false
123
false
123.12.12
true
Test12.123
true
You might use a lookahead to make sure that there is at least a single digit, and repeat matching 1 or more times the dot.
^(?=[A-Za-z]*[0-9])[A-Za-z0-9]+(?:\.[A-Za-z0-9]+)+$
^ Start of string
(?=[A-Za-z]*[0-9]) Assert a digit
[A-Za-z0-9]+ Match 1+ times any of the listed ranges
(?:\.[A-Za-z0-9]+)+ Repeat 1 or more times a dot and again 1 or more of the listed ranges
$ End of string
Regex demo
You can use the regex, \p{Alnum}+(?:\.\p{Alnum}+)+ which can be explained as follows:
\p{Alnum} specifies an alphanumeric character:[\p{Alpha}\p{Digit}]
(?:\.\p{Alnum}+)+ specifies a non-capturing group consisting of a dot followed by one or more alphanumeric characters. The non-capturing group must occur one or more times.
Demo:
public class Main {
public static void main(String[] args) {
String[] arr = { "Test", "Test1", "123", "123.12.12", "Test12.123", "123.123Test", "Test123.123Test",
"Test123.12.12Test" };
String regex = "\\p{Alnum}+(?:\\.\\p{Alnum}+)+";
for (String s : arr) {
System.out.println(s + " => " + (!s.matches(regex) ? "false" : "true"));
}
}
}
Output:
Test => false
Test1 => false
123 => false
123.12.12 => true
Test12.123 => true
123.123Test => true
Test123.123Test => true
Test123.12.12Test => true

3 out of 4 conditions in regex java [duplicate]

This question already has answers here:
The best way to match at least three out of four regex requirements
(2 answers)
Closed 2 years ago.
I am trying to create a java to check strength of a password with regex. The password must pass 3 out of 4 conditions:
lowercase
uppercase
contains digits
has special characters
The code looks like below:
import java.util.*;
public class StringPasswordStrength {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter password: ");
String password = input.nextLine();
boolean test = checkStrength(password);
if (test) {
System.out.print("OK");
}
else {
System.out.print("Not strong enough!");
}
}
public static boolean checkStrength(String password) {
if (password.matches("^(?=.*[a-zA-Z][0-9][!##$%^&*])(?=.{8,})")){
return true;
}
else {
return false;
}
}
}
However when the password is Passw0rd it doesn't accept. How can I change the conditions in regex that the program would accept Passw0rd because it passes 3 out of 4 conditions: uppercase, lowercase and digit?
I would suggest avoiding a potentially cryptic regular expression for this, and instead to provide something easier to read, understand and maintain (albeit more verbose).
Something like this (depending on what your conditions are, of course). For example, a length test should be mandatory:
public boolean isValid(String password) {
// password must contain 3 out of 4 of lowercase, uppercase, digits,
// and others (punctuation, symbols, spaces, etc.).
if (password == null) {
return false;
}
if (password.length() < 8) {
return false;
}
char[] chars = password.toCharArray();
int lowers = 0;
int uppers = 0;
int digits = 0;
int others = 0;
for (Character c : chars) {
if (Character.isLowerCase(c)) {
lowers = 1;
} else if (Character.isUpperCase(c)) {
uppers = 1;
} else if (Character.isDigit(c)) {
digits = 1;
} else {
others = 1;
}
}
// at least 3 out of 4 tests must pass:
return (lowers + uppers + digits + others >= 3);
}
I understand this is not a direct answer to your question, and so may not meet your needs.
I am also deliberately avoiding the discussion about char[] vs. String for password handling in Java - for example, see this post.
EDIT: Removed wording relating to password length, and changed related code to reflect the question.
You could define a set of rules (regex), count how many a given password comply with and compare with the minimum you require. A possible implementation could be:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* Patterns to be tested in your passwords. If you want some of them
* mandatory, you can define them in a "mandatoryPatterns" list and
* check those ones always.
*/
static List<String> patterns = Arrays.asList(
".*[A-Z]+.*",
".*[a-z]+.*"
);
/** Number of required patterns. */
static long requiredPatterns = 1;
/** This functions counts the number of patterns that a password matches. */
static long passwordStrength(String password) {
return patterns.stream().filter(password::matches).count();
}
static boolean checkStrength(String password) {
return passwordStrength(password) >= requiredPatterns;
}
Stream.of("", "foo", "BAR", "FooBar").forEach(pass -> {
System.out.println(pass);
System.out.println(passwordStrength(pass));
System.out.println(checkStrength(pass));
});
Your issue has been pointed out by another user, along with a solution. This is an alternative solution.
Have 4 Pattern objects, one for each requirement
Pattern uppercase = Pattern.compile("[A-Z]");
Pattern number = Pattern.compile("\\d+");
Pattern symbol = Pattern.compile("[+&$%!#]");
Pattern other = ...;
String#matches "compiles" the regex every time it is called, which can be time consuming. By using Pattern objects, you'll be using already-compiled regex patterns.
Add the requirements to a list
List<Pattern> requirements = Arrays.asList(uppercase, number, symbol, other);
Loop over the list of requirements. For each requirement, check if the password matches the requirement. If the element does, increase a counter which tracks how many requirements have already been met.
If the requirements equals 3 (or is greater than 3), return true. If the loop exits gracefully, that means 3 requirements were not met; return false if the loop exits gracefully.
public boolean isStrong(String password) {
int requirementsMet = 0;
for(Pattern req : requirements) {
if(req.matcher(password).matches())
requirementsMet++;
if(requirementsMet >= 3)
return true;
}
return false;
}
I assume the four requirements, of which at three must be met, are as follows. The string must contain:
a letter
a digit
a character in the string "!##$%^&*"
at least 8 characters
Is the use of a regular expression the best way to determine if a password meets three of the four requirements? That may be a valid question but it's not the one being asked or the one that I will attempt to answer. The OP may just be curious: can this problem be solved using a regular expression? Moreover, even if there are better ways to address the problem there is educational value in answers to the specific question that's been posed.
I am not familiar with Java, but I can suggest a regular expression that uses Ruby syntax. Readers unfamiliar with Ruby should be able to understand the expression, and its translation to Java should be straightforward. (If a reader can perform that translation, I would be grateful to see an edit to this answer that provides the Java equivalent at the end.)
r = /
((?=.*[a-z])) # match a lowercase letter in the string in
# a positive lookahead in cap grp 1, 0 times
((?=.*\d)) # match a digit in the string in a positive
# lookahead in cap grp 2, 0 times
((?=.*[!##$%^&*])) # match a special character in in the string
# in a positive lookahead in cap grp 3, 0 times
(.{8,}) # match at least 8 characters in cap grp 4, 0 times
\g<1>\g<2>\g<3> # match conditions 1, 2 and 3
| # or
\g<1>\g<2>\g<4> # match conditions 1, 2 and 4
| # or
\g<1>\g<3>\g<4> # match conditions 1, 3 and 4
| # or
\g<2>\g<3>\g<4> # match conditions 2, 3 and 4
/xi # case indiff & free-spacing regex def modes
\g{2}, for example, is replaced by the sub-expression contained in capture group 2 ((?=.*\d)). The first four lines each contain an expression in a capture group, with the capture group repeated zero times. This is just a device to define the subexpressions in the capture groups for retrieval later.
Let's test some strings.
"Passw0rd".match? r #=> true (a letter, digit and >= 8)
"ab2c#45d".match? r #=> true (all 4 conditions satisfied)
"ab2c#5d".match? r #=> true (a letter, digit and special char)
"ab2c345d".match? r #=> true (a letter, digit and >= 8)
"ab#c?def".match? r #=> true (a letter, special char and >= 8)
"21#6?512".match? r #=> true (a digit, special char and >= 8)
"ab26c4".match? r #=> false (only letter and digit)
"a$b#c".match? r #=> false (only letter and special char)
"abc ef h".match? r #=> false (only letter and >= 8)
"12 45 78".match? r #=> false (only digit and >=8)
"########".match? r #=> false (only special char and >= 8)
"".match r #=> false (no condition matched)
To use named capture groups, ((?=.*[a-z])) would be replaced with, say,
(?<letter>(?=.*[a-z]))
and \g<1>\g<2>\g<3> would be replaced by something like
\g<letter>\g<digit>\g<spec_char>
To answer your question, the sequence in which you have provided
1st: [a-zA-Z] characters
2nd: [0-9] Numbers
3rd: [!##$%^&*] Sp. Chars
The occurrence of literals in this sequence is must.
Abcd1234# will pass but Abcd1234#A will not pass, as A appears again after [!##$%^&*]
And a positive lookahead must include this sequence only. If you provied any special char before, it will not be validated, similarly in your case, characters after number is not expected.
use a positive lookahead for each combination, use groups for each
Try this instead(This is my work after several lookups):
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!##$%&*_])(?!.*[`~^=+/?<>():;-])(?=\S+$).{8,20}$
In this case: any of the provided chars or literals can appear anywhere.
(?=.*[0-9])
(?=.*[a-z])
(?=.*[A-Z])
(?=.*[!##$%&*_])
(?!.*[`~^=+/?<>():;-])
(?=\S+$)

Regular Expression Matching for number only with 2 digits repeated

I am trying to match number which are having 2 digits and those are repeated and the length of number is 7 digits .
I want to match these numbers from java .
example numbers:
3433434
6776767
9000999
Please help to create the regular expression for these pattern numbers
I'd recommend hiding any regexes inside helper methods:
private static boolean matchesCriteria(String s) {
return exactlySevenDigits(s) && containsRepeatedDigits(s);
}
private static boolean exactlySevenDigits(String s) {
return s.matches("\\d{7}");
}
private static boolean containsRepeatedDigits(String s) {
return s.matches(".*(\\d)\\1.*");
}
Example results:
3433434 true
6776767 true
9000999 true
1234567 false (no repeating numbers)
12331233 false (too long)
123356A false (not all digits)
You can do it as follows:
String str = "3433434";
boolean sevenOf2Digits = str.length() == 7 &&
str.matches("(\\d)\\1*+(\\d)(\\1|\\2)*");
System.out.println(sevenOf2Digits);
The first (\\d) captures the first digit in group 1.
\\1 is a backreference to group 1, so the first digit. * is 0 or more of those digits, + makes that possessive, which is required to prevent the next (\\d) from matching the same digit.
The following (\\d) captures the second digit in group 2.
(\\1|\\2)* just matches 0 or more of any combination of the first or second digits.
I separated out the length check for simplicity. If you want a pure regex solution, you can add the length check to your regex in the form of a lookahead by adding (?=.{7}$) to the start of your regex.
"(?=.{7}$)(\\d)\\1*+(\\d)(\\1|\\2)*"
With regex it is a little complicated, I would use this way (Java 8+) instead :
boolean check = myString.chars()
.mapToObj(i -> (char) i)
.collect(Collectors.toSet())
.size() == 2;
The idea is to create a Set with the character of this string, if the size of the Set is 2 then it is correct String else it is not.
Or as Ralf Renz mention in comment, you can use this short way :
boolean check = myString.chars().distinct().count() == 2;
So your final solution should look like this :
boolean check = myString.matches("\\d{7}") && myString.chars().distinct().count() == 2;
(?=^.{7}$)(\d)\1*(?!\1)(\d)(?:\1|\2)*
This should do it. It finds a digit and repeats, then finds a second digit and repeats. Then it checks if the rest of the number is one of those 2.
I'll explain in detail what this does.
(?=^.{7}$): Before starting, make sure there are 7 characters between the start and end. If shorter or longer, fast fails.
(\d)\1*(?!\1)(\d): Get the first digit and save it in a capture group. Then matches if the captured digit is also the next one. If there is only a single digit, the next part will catch that. Last digit should always be different then the first one.
(?:\1|\2): repeat the 2 captured digits 0 or more times.
String regex = "[10]{7}|[20]{7}|[21]{7}|[30]{7}|[31]{7}|[32]{7}|[40]{7}|[41]{7}|[42]{7}|[43]{7}|[50]{7}|[51]{7}|[52]{7}|[53]{7}|[54]{7}|[60]{7}|[61]{7}|[62]{7}|[63]{7}|[64]{7}|[65]{7}|[70]{7}|[71]{7}|[72]{7}|[73]{7}|[74]{7}|[75]{7}|[76]{7}|[80]{7}|[81]{7}|[82]{7}|[83]{7}|[84]{7}|[85]{7}|[86]{7}|[87]{7}|[90]{7}|[91]{7}|[92]{7}|[93]{7}|[94]{7}|[95]{7}|[96]{7}|[97]{7}|[98]{7}";
System.out.println(Pattern.matches(regex, "3433434"));
System.out.println(Pattern.matches(regex, "6776767"));
System.out.println(Pattern.matches(regex, "9000999"));
That should do it. All combinations of two digits with a length of 7.

Regular expression for phrase contain literals and numbers but is not all phrase as a number only with fixed range length

i want to have regular expression to check input character as a-z and 0-9 but i do not want to allow input as just numeric value at all ( must be have at least one alphabetic character)
for example :
413123123123131
not allowed but if have just only one alphabetic character in any place of phrase it's ok
i trying to define correct Regex for that and at final i raised to
[0-9]*[a-z].*
but in now i confused how to defined {x,y} length of phrase i want to have {9,31} but after last * i can not to have length block too i trying to define group but unlucky and not worked
tested at https://www.debuggex.com/
how can i to add it ??
What you seek is
String regex = "(?=.{9,31}$)\\p{Alnum}*\\p{Alpha}\\p{Alnum}*";
Use it with String#matches() / Pattern#matches() method to require a full string match:
if (s.matches(regex)) {
return true;
}
Details
^ - implicit in matches() - matches the start of string
(?=.{9,31}$) - a positive lookahead that requires 9 to 31 any chars other than line break chars from the start to end of the string
\\p{Alnum}* - 0 or more alphanumeric chars
\\p{Alpha} - an ASCII letter
\\p{Alnum}* - 0 or more alphanumeric chars
Java demo:
String lines[] = {"413123123123131", "4131231231231a"};
Pattern p = Pattern.compile("(?=.{9,31}$)\\p{Alnum}*\\p{Alpha}\\p{Alnum}*");
for(String line : lines)
{
Matcher m = p.matcher(line);
if(m.matches()) {
System.out.println(line + ": MATCH");
} else {
System.out.println(line + ": NO MATCH");
}
}
Output:
413123123123131: NO MATCH
4131231231231a: MATCH
This might be what you are looking for.
[0-9a-zA-Z]*[a-zA-Z][0-9a-zA-Z]*
To help explain it, think of the middle term as your one required character and the outer terms as any number of alpha numeric characters.
Edit: to restrict the length of the string as a whole you may have to check that manually after matching. ie.
if (str.length > 9 && str.length < 31)
Wiktor does provide a solution that involves more regex, please look at his for a better regex pattern
Try this Regex:
^(?:(?=[a-z])[a-z0-9]{9,31}|(?=\d.*[a-z])[a-z0-9]{9,31})$
OR a bit shorter form:
^(?:(?=[a-z])|(?=\d.*[a-z]))[a-z0-9]{9,31}$
Demo
Explanation(for the 1st regex):
^ - position before the start of the string
(?=[a-z])[a-z0-9]{9,31} means If the string starts with a letter, then match Letters and digits. minimum 9 and maximum 31
| - OR
(?=\d.*[a-z])[a-z0-9]{9,31} means If the string starts with a digit followed by a letter somewhere in the string, then match letters and digits. Minimum 9 and Maximum 31. This also ensures that If the string starts with a digit and if there is no letter anywhere in the string, there won't be any match
$ - position after the last literal of the string
OUTPUT:
413123123123131 NO MATCH(no alphabets)
kjkhsjkf989089054835werewrew65 MATCH
kdfgfd4374985794379857984379857weorjijuiower NO MATCH(length more than 31)
9087erkjfg9080980984590p465467 MATCH
4131231231231a MATCH
kjdfg34 NO MATCH(Length less than 9)
Here's the regex:
[a-zA-Z\d]*[a-zA-Z][a-zA-Z\d]*
The trick here is to have something that is not optional. The leading and trailing [a-zA-Z\d] has a * quantifier, so they are optional. But the [a-zA-Z] in the middle there is not optional. The string must have a character that matches [a-zA-Z] in order to be matched.
However, you need to check the length of the string with length afterwards and not with regex. I can't think of any way how you can do this in regex.
Actually, I think you can do this regexless pretty easily:
private static boolean matches(String input) {
for (int i = 0 ; i < input.length() ; i++) {
if (Character.isLetter(input.charAt(i))) {
return input.length() >= 9 && input.length() <= 31;
}
}
return false;
}

Regular expression not working as intended

I am using the following regular expression.
(?=.+[a-z])(?=.+[A-Z])(?=.+[^a-zA-Z]).{8,}
my goal is to have a password that has 3 of the 4 properties below
upper case character, lower case character, number, special character
I am using http://rubular.com/r/i26nwsTcaU and http://regexlib.com/RETester.aspx to test the expression with the following inputs
P#55w0rd
password1P
Password1
paSSw0rd
all of these should pass but only the second and fourth are passing at http://rubular.com/r/i26nwsTcaU and all of them pass at http://regexlib.com/RETester.aspx.
I also have the following code that I am using to validate
private void doValidate(String inputStr,String regex) {
Pattern pattern = Pattern.compile(regex);
if(!pattern.matcher(inputStr).matches()){
String errMessage = "";
throw new UniquenessConstraintViolatedException(errMessage);
}
}
this code fails to validate "Password1" which should pass.
as far as the expression goes I understand it like this
must have lower (?=.+[a-z])
must have upper (?=.+[A-Z])
must have non alpha (?=.+[^a-zA-Z])
must be eight characters long .{8,}
can anyone tell me what it is I'm doing wrong.
Thanks in advance.
Essentially, the .+ subexpressions are to blame, they should be .*. Otherwise, the lookahead part looks for lower case, upper case or non-alpha but a character of each corresponding type does not count if it is the first one in string. So, you are validating not the password, but the password with first char truncated. While #Cfreak is not right, he is close - what you are doing would not be possible with normal regex and you would have to use what he suggests. With the lookahead groups - (?=) - it is possible to do what you need. Still, personally I would rather code it like #Cfreak suggests - it is more readable and your intentions are clearer from the code. Complex regular expressions tend to be hard to write but close to impossible to read, debug, or improve after some time.
Your regex right now says you must have 1 or more lowercase characters, followed by 1 or more upper case characters followed by 1 or more upper or lowercase characters, followed by 8 characters or more.
Regex can't do AND unless you specify where a particular character appears. You basically need to split each part of your regex into it's own regex and check each one. You can check the length with whatever string length method Java has (sorry i'm not a java dev so I don't know what it is off my head).
Pseudo code:
if( regexForLower && regexForUpper && regexForSpecial && string.length == 8 ) {
// pass
}
As I said in a comment, position-0 capital letters are being ignored.
Here's a regex to which all four passwords match.
(?=.+\\d)(?=.+[a-z])(?=\\w*[A-Z]).{8,}
I wouldn't use such a regex.
it is hard to understand
hard to debug
hard to extend
you can't do much with its result
If you like to tell the client what is wrong with his password, you have investigate the password again. In real world environments you might want to support characters from foreign locales.
import java.util.*;
/**
Pwtest
#author Stefan Wagner
#date Fr 11. Mai 20:55:38 CEST 2012
*/
public class Pwtest
{
public int boolcount (boolean [] arr) {
int sum = 0;
for (boolean b : arr)
if (b)
++sum;
return sum;
}
public boolean [] rulesMatch (String [] groups, String password) {
int idx = 0;
boolean [] matches = new boolean [groups.length];
for (String g: groups) {
matches[idx] = (password.matches (".*" + g + ".*"));
++idx;
}
return matches;
}
public Pwtest ()
{
String [] groups = new String [] {"[a-z]", "[A-Z]", "[0-9]", "[^a-zA-Z0-9]"};
String [] pwl = new String [] {"P#55w0rd", "password1P", "Password1", "paSSw0rd", "onlylower", "ONLYUPPER", "1234", ",:?!"};
List <boolean[]> lii = new ArrayList <boolean[]> ();
for (String password: pwl) {
lii.add (rulesMatch (groups, password));
}
for (int i = 0 ; i < lii.size (); ++i) {
boolean [] matches = lii.get (i);
String pw = pwl[i];
if (boolcount (matches) < 3) {
System.out.print ("Password:\t" + pw + " violates rule (s): ");
int idx = 0;
for (boolean b: matches) {
if (! b)
System.out.print (groups[idx] + " ");
++idx;
}
System.out.println ();
}
else System.out.println ("Password:\t" + pw + " fine ");
}
}
public static void main (String args[])
{
new Pwtest ();
}
}
Output:
Password: P#55w0rd fine
Password: password1P fine
Password: Password1 fine
Password: paSSw0rd fine
Password: onlylower violates rule (s): [A-Z] [0-9] [^a-zA-Z0-9]
Password: ONLYUPPER violates rule (s): [a-z] [0-9] [^a-zA-Z0-9]
Password: 1234 violates rule (s): [a-z] [A-Z] [^a-zA-Z0-9]
Password: ,:?! violates rule (s): [a-z] [A-Z] [0-9]
Password: Übergrößen345 fine
Password: 345ÄÜö violates rule (s): [a-z] [A-Z]

Categories

Resources