I am trying to see whether a string contains at least a digit or a lowercase or an uppercase.
I have written something like this:
int combinations = 0;
string pass = "!!!AAabas1";
if (pass.matches("[0-9]")) {
combinations = combinations + 10;
}
if (pass.matches("[a-z]")) {
combinations =combinations + 26;
}
if (pass.matches("[A-Z]")) {
combinations =combinations + 26;
}
However I don't understand why I cannot get combinations to go to 36. They just remain at 0. What am I doing wrong?
You could use Pattern instead, I think "matches" method looks for the whole string to match the regular expression.
Try the next code:
int combinations = 0;
String pass = "!!AAabas1";
if (Pattern.compile("[0-9]").matcher(pass).find()) {
combinations = combinations + 10;
}
if (Pattern.compile("[a-z]").matcher(pass).find()) {
combinations = combinations + 26;
}
if (Pattern.compile("[A-Z]").matcher(pass).find()) {
combinations = combinations + 26;
}
Here's my attempt. Note, this uses unicode categories for validation so is non-latin language friendly.
import java.util.regex.Pattern;
public class PasswordValidator {
public static void main(String[] args) {
final PasswordValidator passwordValidator = new PasswordValidator();
for (String password : new String[] { "abc", "abc123", "ABC123", "abc123ABC", "!!!AAabas1", "гшщз",
"гшщзЧСМИ22" }) {
System.out.printf("Password '%s' is %s%n", password, passwordValidator.isValidPassword(password) ? "ok"
: "INVALID");
}
}
private static final Pattern LOWER_CASE = Pattern.compile("\\p{Lu}");
private static final Pattern UPPER_CASE = Pattern.compile("\\p{Ll}");
private static final Pattern DECIMAL_DIGIT = Pattern.compile("\\p{Nd}");
/**
* Determine if a password is valid.
*
* <p>
* A password is considered valid if it contains:
* <ul>
* <li>At least one lower-case letter</li>
* <li>At least one upper-case letter</li>
* <li>At least one digit</li>
* </p>
*
* #param password
* password to validate
* #return True if the password is considered valid, otherwise false
*/
public boolean isValidPassword(final String password) {
return containsDigit(password) && containsLowerCase(password) && containsUpperCase(password);
}
private boolean containsDigit(final String str) {
return DECIMAL_DIGIT.matcher(str).find();
}
private boolean containsUpperCase(final String str) {
return UPPER_CASE.matcher(str).find();
}
private boolean containsLowerCase(final String str) {
return LOWER_CASE.matcher(str).find();
}
}
Here's the output:
Password 'abc' is INVALID
Password 'abc123' is INVALID
Password 'ABC123' is INVALID
Password 'abc123ABC' is ok
Password '!!!AAabas1' is ok
Password 'гшщз' is INVALID
Password 'гшщзЧСМИ22' is ok
The problem is that matches tries to match the entire input string.
Instead, try creating a Pattern, then from there create a Matcher, and then use the find method.
The Pattern javadoc should help a great deal.
While using a regex for this can obviously work, Guava's CharMatcher class might be a bit more appropriate to what you're trying to do:
if (CharMatcher.inRange('0', '9').matchesAnyOf(pass))
combinations += 10;
if (CharMatcher.inRange('a', 'z').matchesAnyOf(pass))
combinations += 26;
if (CharMatcher.inRange('A', 'Z').matchesAnyOf(pass))
combinations += 26;
String str_rno = "CooL8";
boolean Flag = false;
String[] parts = str_rno.split("");
for (int i = 0; i < str_rno.length(); i++) {
String part1 = parts[i + 1];
if (Character.isDigit(str_rno.charAt(i))) {
System.out.println(" " + i + " " + part1 + " digit");
Flag = true;
} else {
System.out.println(" " + i + " " + part1 + " char ");
}
}
if(Flag==true){
Toast.makeText(getApplicationContext(),"String contain 1 digit",Toast.LENGTH_SHORT).show();
}
if(Flag==flase){
Toast.makeText(getApplicationContext(),"String not contain 1 digit",Toast.LENGTH_SHORT).show();
}
If you don't want to or are not allowed to use a regex you can also use the following method:
public static boolean containsNumber(String value) {
for (int i = 0; i < value.length(); i++) {
if (Character.isDigit(value.charAt(i)))
return true;
}
return false;
}
It goes through the string until it finds a number. If no number was found, then false is returned. However, I suspect that for longer strings the regex variant has better performance.
Related
write a function which increments a string, to create a new string.
If the string already ends with a number, the number should be incremented by 1.
If the string does not end with a number. the number 1 should be appended to the new string.
Examples:
foo - foo1
foobar23 - foobar24
foo0042 - foo0043
foo9 - foo10
foo099 - foo100
Attention: If the number has leading zeros the amount of digits should be considered.
The program passed tests on the CodeWars platform, except for one
For input string: "1712031362069931272877416673"
she falls on it
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
but in IJ it works correctly ...
Any idea why?
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
System.out.println(incrementString("foo001"));
System.out.println(incrementString("33275375531813209960"));
System.out.println(incrementString("0000004617702678077138438340108"));
}
public static String incrementString(String str) {
boolean isNumeric = str.chars().allMatch( Character::isDigit );
if(str.isEmpty())
return "1";
else if (isNumeric) {
BigInteger b = new BigInteger(str);
return String.format("%0"+str.length() + "d",b.add(BigInteger.valueOf(1)));
}
String timeRegex = "(.*)(\\D)([0-9]*)";
Pattern pattern = Pattern.compile(timeRegex);
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
String sec = matcher.group(3);
StringBuilder sb = new StringBuilder();
if (sec.isEmpty()) {
sec = "0";
return str + sb+(Integer.parseInt(sec) + 1);
} else {
int length = String.valueOf(Integer.parseInt(sec) + 1).length();
if (sec.length() > length) {
for (int i = length; i < sec.length(); i++) {
sb.append("0");
}
}
return str.substring(0,str.length() - sec.length()) + String.format("%0"+sec.length() + "d",Integer.parseInt(sec)+1);
}
}
else
return "";
}
}
The issue is with Integer.parseInt(sec) when trying to parse a value too long to fix in a int (max is 2 billion)
You need to use BigInteger everywhere, also there is much useless code. You can also capture the zeros in the first group of the regex, so you don't have leading zeros to take care
public static String incrementString(String str) {
boolean isNumeric = str.chars().allMatch(Character::isDigit);
if (str.isEmpty()) {
return "1";
} else if (isNumeric) {
BigInteger b = new BigInteger(str);
return String.format("%0" + str.length() + "d", b.add(BigInteger.ONE));
}
String timeRegex = "(.*\\D0*)([1-9][0-9]*)";
Matcher matcher = Pattern.compile(timeRegex).matcher(str);
if (matcher.matches()) {
String sec = matcher.group(2);
if (sec.isEmpty()) {
return str + 1;
} else {
BigInteger new_value = new BigInteger(sec).add(BigInteger.ONE);
return matcher.group(1) + new_value;
}
}
return "";
}
How would you solve this problem by hand? I'll bet you wouldn't require a calculator.
The way I would do would be to just look at the last character in the string:
If the string is empty or the last character is not a digit, append the character 1.
If the last character is one of the digits 0 to 8, change it to the next digit.
If the last character is the digit 9:
Remove all the trailing 9s
Apply whichever of (1) or (2) above is appropriate.
Append the same number of 0s as the number of 9s you removed.
You can implement that simple algorithm in a few lines, without BigInteger and without regexes.
This seems to work, although I didn't test it thoroughly with different Unicode scripts (and I'm really not a Java programmer):
public static String incrementString(String str) {
if (str.isEmpty())
return "1";
char lastChar = str.charAt(str.length()-1);
if (!Character.isDigit(lastChar))
return str + "1";
String prefix = str.substring(0, str.length()-1);
if (Character.digit(lastChar, 10) != 9)
return prefix + (char)(lastChar + 1);
return incrementString(prefix) + (char)(lastChar - 9);
}
This post is an update to this one : get specific character in a string with regex and remove unused zero
In the first place, i wanted to remove with an regular expression the unused zero in the last match.
I found that the regular expression is a bit overkill for what i need.
Here is what i would like now,
I would like to use split() method
to get from this :
String myString = "2020-LI50532-3329-00100"
this :
String data1 = "2020"
String data2 = "LI50532"
String data3 = "3329"
String data4 = "00100"
So then i can remove from the LAST data the unused Zero
to convert "00100" in "100"
And then concatenate all the data to get this
"2020-LI50532-3329-100"
Im not familiar with the split method, if anyone can enlight me about this ^^
You can use substring method to get rid of the leading zeros...
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + data[3]);
String result = sb.toString();
System.out.println(result);
Assuming that we want to remove the leading zeroes of ONLY the last block, maybe we can:
Extract the last block
Convert it to Integer and back to String to remove leading zeroes
Replace the last block with the String obtained in above step
Something like this:
public String removeLeadingZeroesFromLastBlock(String text) {
int indexOfLastDelimiter = text.lastIndexOf('-');
if (indexOfLastDelimiter >= 0) {
String lastBlock = text.substring(indexOfLastDelimiter + 1);
String lastBlockWithoutLeadingZeroes = String.valueOf(Integer.valueOf(lastBlock)); // will throw exception if last block is not an int
return text.substring(0, indexOfLastDelimiter + 1).concat(lastBlockWithoutLeadingZeroes);
}
return text;
}
Solution using regex:
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
return str.replaceAll("0+(?=[1-9]\\d*$)", "");
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
Explanation of the regex:
One or more zeros followed by a non-zero digit which can be optionally followed by any digit(s) until the end of the string (specified by $).
Solution without using regex:
You can do it also by using Integer.parseInt which can parse a string like 00100 into 100.
public class Main {
public static void main(String[] args) {
// Test
System.out.println(parse("2020-LI50532-3329-00100"));
System.out.println(parse("2020-LI50532-3329-00001"));
System.out.println(parse("2020-LI50532-03329-00100"));
System.out.println(parse("2020-LI50532-03329-00001"));
}
static String parse(String str) {
String[] parts = str.split("-");
try {
parts[parts.length - 1] = String.valueOf(Integer.parseInt(parts[parts.length - 1]));
} catch (NumberFormatException e) {
// Do nothing
}
return String.join("-", parts);
}
}
Output:
2020-LI50532-3329-100
2020-LI50532-3329-1
2020-LI50532-03329-100
2020-LI50532-03329-1
you can convert the last string portion to integer type like below for removing unused zeros:
String myString = "2020-LI50532-3329-00100";
String[] data = myString.split("-");
data[3] = data[3].substring(2);
StringBuilder sb = new StringBuilder();
sb.append(data[0] + "-" + data[1] + "-" + data[2] + "-" + Integer.parseInt(data[3]));
String result = sb.toString();
System.out.println(result);
You should avoid String manipulation where possible and rely on existing types in the Java language. One such type is the Integer. It looks like your code consists of 4 parts - Year (Integer) - String - Integer - Integer.
So to properly validate it I would use the following code:
Scanner scan = new Scanner("2020-LI50532-3329-00100");
scan.useDelimiter("-");
Integer firstPart = scan.nextInt();
String secondPart = scan.next();
Integer thirdPart = scan.nextInt();
Integer fourthPart = scan.nextInt();
Or alternatively something like:
String str = "00100";
int num = Integer.parseInt(str);
System.out.println(num);
If you want to reconstruct your original value, you should probably use a NumberFormat to add the missing 0s.
The main points are:
Always try to reuse existing code and tools available in your language
Always try to use available types (LocalDate, Integer, Long)
Create your own types (classes) and use the expressiveness of the Object Oriented language
public class Test {
public static void main(String[] args) {
System.out.println(trimLeadingZeroesFromLastPart("2020-LI50532-03329-00100"));
}
private static String trimLeadingZeroesFromLastPart(String input) {
String delem = "-";
String result = "";
if (input != null && !input.isEmpty()) {
String[] data = input.split(delem);
StringBuilder tempStrBldr = new StringBuilder();
for (int idx = 0; idx < data.length; idx++) {
if (idx == data.length - 1) {
tempStrBldr.append(trimLeadingZeroes(data[idx]));
} else {
tempStrBldr.append(data[idx]);
}
tempStrBldr.append(delem);
}
result = tempStrBldr.substring(0, tempStrBldr.length() - 1);
}
return result;
}
private static String trimLeadingZeroes(String input) {
int idx;
for (idx = 0; idx < input.length() - 1; idx++) {
if (input.charAt(idx) != '0') {
break;
}
}
return input.substring(idx);
}
}
Output:
2020-LI50532-3329-100
I have a string in format AB123. I want to split it between the AB and 123 so AB123 becomes AB 123. The contents of the string can differ but the format stays the same. Is there a way to do this?
Following up with the latest information you provided (2 letters then 3 numbers):
myString.subString(0, 2) + " " + myString.subString(2)
What this does: you split your input string myString at the 2nd character and append a space at this position.
Explanation: \D represents non-digit and \d represents a digit in a regular expression and I used ternary operation in the regex to split charter to the number.
String string = "AB123";
String[] split = string.split("(?<=\\D)(?=\\d)");
System.out.println(split[0]+" "+split[1]);
Try
String a = "abcd1234";
int i;
for(i = 0; i < a.length(); i++){
char c = a.charAt(i);
if( '0' <= c && c <= '9' )
break;
}
String alphaPart = a.substring(0, i);
String numberPart = a.substring(i);
Hope this helps
Although I would personally use the method provided in #RakeshMothukur's answer, since it also works when the letter or digit counts increase/decrease later on, I wanted to provide an additional method to insert the space between the two letters and three digits:
String str = "AB123";
StringBuilder sb = new StringBuilder(str);
sb.insert(2, " "); // Insert a space at 0-based index 2; a.k.a. after the first 2 characters
String result = sb.toString(); // Convert the StringBuilder back to a String
Try it online.
Here you go. I wrote it in very simple way to make things clear.
What it does is : After it takes user input, it converts the string into Char array and it checks single character if its INT or non INT.
In each iteration it compares the data type with the prev character and prints accordingly.
Alternate Solutions
1) Using ASCII range (difficulty = easy)
2) Override a method and check 2 variables at a time. (difficulty = Intermediate)
import org.omg.CORBA.INTERNAL;
import java.io.InputStreamReader;
import java.util.*;
import java.io.BufferedReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
char[] s = br.readLine().toCharArray();
int prevflag, flag = 0;
for (int i = 0; i < s.length; i++) {
int a = Character.getNumericValue(s[i]);
String b = String.valueOf(s[i]);
prevflag = flag;
flag = checktype(a, b);
if ((prevflag == flag) || (i == 0))
System.out.print(s[i]);
else
System.out.print(" " + s[i]);
}
}
public static int checktype(int x, String y) {
int flag = 0;
if (String.valueOf(x).equals(y))
flag = 1; // INT
else
flag = 2; // non INT
return flag;
}
}
I was waiting for a compile to finish before heading out, so threw together a slightly over-engineered example with basic error checking and a test.
import java.text.ParseException;
import java.util.LinkedList;
public class Main {
static public class ParsedData {
public final String prefix;
public final Integer number;
public ParsedData(String _prefix, Integer _number) {
prefix = _prefix;
number = _number;
}
#Override
public String toString() {
return prefix + "\t" + number.toString();
}
}
static final String TEST_DATA[] = {"AB123", "JX7272", "FX402", "ADF123", "JD3Q2", "QB778"};
public static void main(String[] args) {
parseDataArray(TEST_DATA);
}
public static ParsedData[] parseDataArray(String[] inputs) {
LinkedList<ParsedData> results = new LinkedList<ParsedData>();
for (String s : TEST_DATA) {
try {
System.out.println("Parsing: " + s);
if (s.length() != 5) throw new ParseException("Input Length incorrect: " + s.length(), 0);
String _prefix = s.substring(0, 2);
Integer _num = Integer.parseInt(s.substring(2));
results.add(new ParsedData(_prefix, _num));
} catch (ParseException | NumberFormatException e) {
System.out.printf("\"%s\", %s\n", s, e.toString());
}
}
return results.toArray(new ParsedData[results.size()]);
}
}
I am working on some socket programming stuff and attempting to match some strings. The format is as follows:
1.) Some text
where the one represents any number, and some text refers to anything (including letters, numbers, quotation marks, etc).
I tried using [0-9]*\\.\\).* but it doesn't return a match. What am I doing wrong and how do I fix it?
Edit
As requested, here is my code:
/** Parses data returned by the server */
public void getSocketData(String data) {
String[] lines = data.split("\\r?\\n");
this.fileHosts = new String[lines.length];
Pattern p = Pattern.compile("[0-9]*\\.\\).*");
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (p.matcher(line).matches()) {
//The format is: 1.) "b.jpg" from "192.168.1.101:40000"
String[] info = line.split("\"");
this.fileHosts[i] = info[3]; //this should now contain <addr:port>
System.out.println("Adding " + fileHosts[i] + " to fileHosts");
}
else {
System.out.println("No Match!");
}
}
}//getSocketData
This works for me:
public static void main(String args[]) {
String s = "1.) Some text";
System.out.println(s.replaceFirst("^[0-9]+\\.\\).*$","matched"));
}
Output:
matched
EDIT: Same result with the following:
String s = "1.) \"b.jpg\" from \"192.168.1.101:40000\"";
That is the example in the comment in your code
EDIT2: I try also your code:
String s = "1.) \"b.jpg\" from \"192.168.1.101:40000\"";
Pattern p = Pattern.compile("^[0-9]+\\.\\).*$"); // works also if you use * instead of +
if (p.matcher(s).matches()) {
System.out.println("match");
}
else {
System.out.println("No Match!");
}
The result is
match
Try using this regex: ^[0-9]+\\.\\).*$
it may seem simple but it posses lots of bugs
I tried this way:
String s = gameList[0].toString();
s.replaceFirst(String.valueOf(s.charAt(0)),String.valueOf(Character.toUpperCase(s.charAt(0))) );
and it throws an exception
another try i had was :
String s = gameList[0].toString();
char c = Character.toUpperCase(gameList[0].charAt(0));
gameList[0] = s.subSequence(1, s.length());
rhis one also throws an Exception
/**
* returns the string, the first char lowercase
*
* #param target
* #return
*/
public final static String asLowerCaseFirstChar(final String target) {
if ((target == null) || (target.length() == 0)) {
return target; // You could omit this check and simply live with an
// exception if you like
}
return Character.toLowerCase(target.charAt(0))
+ (target.length() > 1 ? target.substring(1) : "");
}
/**
* returns the string, the first char uppercase
*
* #param target
* #return
*/
public final static String asUpperCaseFirstChar(final String target) {
if ((target == null) || (target.length() == 0)) {
return target; // You could omit this check and simply live with an
// exception if you like
}
return Character.toUpperCase(target.charAt(0))
+ (target.length() > 1 ? target.substring(1) : "");
}
. . . or do it all in an array. Here's something similar.
String titleize(String source){
boolean cap = true;
char[] out = source.toCharArray();
int i, len = source.length();
for(i=0; i<len; i++){
if(Character.isWhitespace(out[i])){
cap = true;
continue;
}
if(cap){
out[i] = Character.toUpperCase(out[i]);
cap = false;
}
}
return new String(out);
}
On String being immutable
Regarding your first attempt:
String s = gameList[0].toString();
s.replaceFirst(...);
Java strings are immutable. You can't invoke a method on a string instance and expect the method to modify that string. replaceFirst instead returns a new string. This means that these kinds of usage are wrong:
s1.trim();
s2.replace("x", "y");
Instead, you'd want to do something like this:
s1 = s1.trim();
s2 = s2.replace("x", "y");
As for changing the first letter of a CharSequence to uppercase, something like this works (as seen on ideone.com):
static public CharSequence upperFirst(CharSequence s) {
if (s.length() == 0) {
return s;
} else {
return Character.toUpperCase(s.charAt(0))
+ s.subSequence(1, s.length()).toString();
}
}
public static void main(String[] args) {
String[] tests = {
"xyz", "123 abc", "x", ""
};
for (String s : tests) {
System.out.printf("[%s]->[%s]%n", s, upperFirst(s));
}
// [xyz]->[Xyz]
// [123 abc]->[123 abc]
// [x]->[X]
// []->[]
StringBuilder sb = new StringBuilder("blah");
System.out.println(upperFirst(sb));
// prints "Blah"
}
This of course will throw NullPointerException if s == null. This is often an appropriate behavior.
I like to use this simpler solution for names, where toUp is an array of full names split by (" "):
for (String name : toUp) {
result = result + Character.toUpperCase(name.charAt(0)) +
name.substring(1).toLowerCase() + " ";
}
And this modified solution could be used to uppercase only the first letter of a full String, again toUp is a list of strings:
for (String line : toUp) {
result = result + Character.toUpperCase(line.charAt(0)) +
line.substring(1).toLowerCase();
}
Hope this helps.