This question already has answers here:
Using Regex to generate Strings rather than match them
(12 answers)
Closed 7 years ago.
I want to get a list of all possible values for a regular expression.
Input :
2W
9WW
7W0W3
where W can be any digit from 0 to 9. i.e. W = [0-9]
Output:
20,21,22,....29
900,901,...910,911,...999
70003,70013,70023,...71003,72003,...79093
What I did :
I'm using Java and decided to create an ArrayList of Integers.
I created a method ArrayList<Integer> getNumbers(String regex).
ArrayList<Integer> getNumbers(String regex){
ArrayList<Integer> fullList = new ArrayList<Integer>();
char[] cArray = regex.toCharArray(); //converted the string into a character array.
for(int i=1;i<cArray.length;i++) {
if(cArray[i] == 'W') {
for(int j=0;j<10;j++) {
//I'm not sure what goes here
fullList.add(the number with 'w' at this index replaced by 'j');
}
}
}
return fullList;
}
Is there any better way or library functions available to generate all such numbers?
How can I achieve this?
This is not quite a regex-based problem, but from an algorithmic perspective you can do the followings:
Count the number of W's in your string.
Based on the number of W's, create the product of range(0,9), for example if you have 2 W you need to create the products of two [0...9] lists that will be something like 0,0-0,1-0,2-...-9,9.
Loop over the combinations and replace them with a simple string formatting. For instance when you are iterating over a triple combination suppose with 3 variables i,j,k you want want to replace them in a string like 7W0W3W, you can do "7%d0%dW%d"%(i,j,k).
And if you are looking for a general regex to wrap all the cases you can use a regex like (w) (w in a capture group) then you need to first access to position of the match groups and replace them with combination items (i,j,k,..).
It's better to call the input string as "pattern", not "regular expression". Also it's probably better to create a "virtual" list which generates the strings on demand. Here's the sample implementation:
public static List<String> getNumbers(String pattern) {
final char[] chars = pattern.toCharArray();
int size = 1;
for(char ch : chars)
if(ch == 'W') {
if(size == 1_000_000_000)
throw new IllegalArgumentException("Too many 'W' to fit the list");
size*=10;
}
final int finalSize = size;
return new AbstractList<String>() {
#Override
public String get(int index) {
char[] res = chars.clone();
for(int i=res.length-1; i>=0; i--) {
if(res[i] == 'W') {
res[i] = (char) ('0'+(index % 10));
index/=10;
}
}
return new String(res);
}
#Override
public int size() {
return finalSize;
}
};
}
First we count the number of 'W' chars and calculate the target list size accordingly. Then we return an implementation of AbstractList which for given list index replaces the 'W' symbols with the remainders of index division by 10. This list does not take the memory, it generates the String only when you request it. If you want to get the hard-copy of such list, you can use new ArrayList<>(getNumbers(pattern)).
Related
This question already has answers here:
Using Regex to generate Strings rather than match them
(12 answers)
Closed 9 months ago.
This post was edited and submitted for review 9 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I am trying to write a program that would ask the user how many security codes he wants to generate, then it would output as many codes as he requested in an array.
The security code should be 7 characters long and have the following format: NNNNLLL, where N is a random number and L is a random upper case letter.
The method should create security codes with the above format by randomly selecting the characters, i.e. numbers and letters.
I am expecting the program to output something like this if a user selects to generate 4 codes:
“2394QAB”
“2821TSZ”
“7173AAY”
“2236WQA”
I can only use the methods for this code learned in my course and I cannot use other libraries like regex, that is why I am trying it like this.
This is the code I have done so far:
import java.util.Random;
public class ItemChecker{
private StringBuffer strBuff;
private String[] codes;
private String CodeLetters, CodeNumbers;
private int[] RandomNums;
public ItemChecker(){
strBuff=new StringBuffer();
}
public String[] getCodes(int[] amount){
codes=new String[amount.length];
for(int i=0;i<amount.length;i++)
{
CodeLetters="";
strBuff=new StringBuffer();
for(int j=0;j<4;j++)
{
Random RandomNumber=new Random();
int randomIndex=RandomNumber.nextInt(RandomNums.length);
CodeNumbers.append(RandomNumber[randomIndex]);
}
for(int j=0;j<3;j++)
{
Random RandomLetter=new Random();
char c =(char)(RandomLetter.nextInt(26)+'a');
CodeLetters+=c;
}
codes[i]=CodeNumbers+CodeLetters;
}
}
}
My intention is to create 4 random digits and 3 random letters and add them together in a string to make the code. However, the code doesn't generate the random codes and I have no clue how to proceed from here.
Within your getCodes method there are a couple of mistakes. A StringBuiler would be more appropriate for this task, instead of using a StringBuffer or chaining strings with the + operator. As a matter of fact, each time you're performing a concatenation with the + operator you're creating a new string in memory, rather than working on a same instance, this is not that efficient. Also, when you're adding an offset to the random value representing an upper case letter, you're adding the lower case 'a', instead of the upper case 'A'.
In your program, you could define a static method to offer the code generation service as a general utility and then invoke it within your getCodes method.
In the utility method, you could declare a Random object to get random int values. Then, with a first for loop, you could generate random values between 0 included and 10 excluded, and append them to a StringBuilder object. The String class represents immutable objects, so you need to use a StringBuilder to build one. As said above, chaining strings with the + operator will create new instances at each concatenation, you're not working on the same object.
Then, with a second for loop you could generate random values from 0 to 27 excluded, add to every value the offset 65, representing the upper case 'A' letter (lower case 'a' has value 97), and then cast this int value to a char to get its character representation. Finally, append the char to your StringBuilder instance.
Here is an implementation:
public class Main {
public static void main(String[] args) {
System.out.println(getSecurityCode());
}
public String[] getCodes(int[] amount) {
String[] codes = new String[amount.length];
for (int i = 0; i < codes.length; i++) {
codes[i] = getSecurityCode();
}
return codes;
}
public static String getSecurityCode() {
Random rand = new Random();
StringBuilder strBuilder = new StringBuilder();
//Appending 4 random digits
for (int i = 0; i < 4; i++) {
//nextInt(10) returns a value between 0 (included) and 10 (excluded)
strBuilder.append(rand.nextInt(10));
}
//Appending 3 random upper case letters
for (int i = 0; i < 3; i++) {
//rand.nextInt(27) returns a random value between 0 and 26 included to represent an alphabet letter.
//This value is added with the offset 65 which represents the upper case A letter.
//Finally, this value is cast as a char or else it would append its int value
strBuilder.append((char)(65 + rand.nextInt(27)));
}
return strBuilder.toString();
}
}
To simplify your code that generate the password you could use RandomStringUtils from org.apache.commons.lang3.RandomStringUtils like described in this great tutorial https://www.baeldung.com/java-random-string.
You just have to generate 2 strings :
One with 4 digits
One with 3 letters to uppercase
And concat both.
Here's How
public static String getSecurityCode() {
//generate 4 numbers only
String generatedNumbers = RandomStringUtils.random(4, false, true);
//generate 3 letters only
String generatedLetters = RandomStringUtils.random(3, true, false).toUpperCase();
return generatedNumbers + generatedLetters;
}
Or with StringBuilder
public static String getSecurityCode2() {
StringBuilder stb=new StringBuilder(7);
//generate 4 numbers only
stb.append(RandomStringUtils.random(4, false, true));
//generate 3 letters only
stb.append( RandomStringUtils.random(3, true, false).toUpperCase());
return stb.toString();
}
Another way of doing this is to utilize StringBuilder's appendCodePoint method for this:
int number= random.nextInt(10000); //generate any number between 0 to 9999
StringBuilder builder=new StringBuilder();
for(int i=0;i<3;i++) {
builder.appendCodePoint(65+random.nextInt(26));
}
String result=number+builder.toString();
System.out.println(result);
Is there a quick way to select the longest of three strings (s1,s2,s3) using if/else method?
I'm using Java
I have tried using something like this
if (s1.length() > s2.length()) {
System.out.println(s1); ...
but did not get it right.
Don't try to program all possible combinations with an if-else construct, as the complexity will grow exponentially if you add more strings.
This solution works well for a small number of strings with a linear complexity:
string longest = s1;
if (s2.length() > longest.length()) {
longest = s2;
}
if (s3.length() > longest.length()) {
longest = s3;
}
System.out.println(longest);
For a lager number of strings, put them in collection and find the longest using a loop.
You can use if, else if, else in C# (if you aren't actually using Java which it looks like you are) to handle this.
string current = str;
if(str2.Length > current.Length)
{
current = str2;
}
if (str3.Length > current.Length)
{
current = str3;
}
Unless using if/else is a requirement of this code, using a collection and LINQ will be a cleaner option.
List<string> strList = new List<string>
{
"str",
"strLen",
"strLength"
};
// This aggregate will return the longest string in a list.
string longestStr = strList.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
string a = "123";
string b = "1322";
string c = "122332";
if (a.Length > b.Length && a.Length > c.Length)
{
Console.WriteLine(a);
}
else if (b.Length > c.Length)
{
Console.WriteLine(b);
}
else
{
Console.WriteLine(c);
}
}
if/then/else constructs Java is same as C#. you can use solutions above. LINQ is like Streams in Java. In Java you can code:
public static void main(String args[]) {
printtLongest ("VampireApi","C#-Api","Java Api");
}
public static void printtLongest(String ... strings){
java.util.Arrays
.stream(strings)
.sorted(java.util.Comparator.comparingInt(String::length).reversed())
.findFirst().ifPresent(System.out::println);
}
create an array and input a string into each part of the array(can do this through loop or manually add- String[] st= new st String[]; then you can: st[0]="aaa"; st[1]="eff"... after this you can use a loop which takes the current length of the string at the array[i] and use a variable max(which will start at 0) which keep the highest length using the Math.max() function.
if the length(which is an integer) is larger then max then you save the string in a string variable and the loop will go through every string In your array and will update the max if needed. after this you can either return or print the string which is the longest.
this is one of many ways. or you could do three if's to check. this method would work great with larger amount of strings.
Not using if-else as the OP asked, but a cleaner solution is this:
void longest(String a, String b, String c) {
String[] triplet = {a, b, c};
Arrays.sort(triplet, Comparator.comparingInt(String::length));
System.out.println(triplet[2]);
}
Trying to write a java method that will take a string, loop through it and where it finds a vowel (A,E,I,O,U,Y) replace it with the vowel plus "OB".
I've written the below but it isn't working as I'd expect and doesn't seem to be matching the current character in my string with the vowels from my list. (The program compiles and runs so it isn't an issue with not importing necessary bits at the beginning. The input string will always be uppercase and only contain alphas.) I'm struggling to figure out where I'm going wrong.
Can anyone help?
public static String obifyText(String text) {
String[] myList = new String[] {"A","E","I","O","U","Y"};
StringBuilder tempText = new StringBuilder(text);
String obify = "OB";
for (int i = 0; i < text.length() -1 ; i ++ ) {
if ( Arrays.asList(myList).contains(tempText.charAt(i)) ) {
System.out.println(tempText.charAt(i)+" found.");
tempText = tempText.insert((i+1),obify);
}
}
text = tempText.toString();
return text;
}
Don't play with indexes.
Managing with indexes could be difficult when you are dealing with changing the string.
Loop on the chars itself as follows:
public static void main(String[] args){
String[] myList = new String[] {"A","E","I","O","U","Y"};
String text = "AEE";
StringBuilder tempText = new StringBuilder("");
String obify = "OB";
for (char c : text.toCharArray()){
tempText = tempText.append(c);
if ( Arrays.asList(myList).contains(c+"") ) {
System.out.println(c+" found.");
tempText = tempText.append(obify);
}
}
text = tempText.toString();
System.out.println(text);
}
OUTPUT:
A found.
E found.
E found.
AOBEOBEOB
charAt returns a char, but myList stores String elements. An array of Strings can never contain values of char. Your if statement never runs.
You can convert the char value to a string:
Arrays.asList(myList).contains(Character.toString(tempText.charAt(i)))
There's just one more problem with your code.
When the code inserts OB after a vowel, there is a side effect: a new vowel O is created. Your code then tries to insert OB after the new O. This is undesired, right?
To make it not do this, you can loop from the end of the string to the start:
for (int i = text.length() - 1; i >= 0 ; i--) {
If this is not a homework question to practice using StringBuilder or for loops, here's a one liner solution using regex:
return text.replaceAll("([AEIOUY])", "$1OB");
You compare two different types in Arrays.asList(myList).contains(tempText.charAt(i)), Arrays.asList(myList) is a List<String> and tempText.charAt is a char. So the contains check will never result in true.
One possible fix, change myList to Character[]
Character[] myList = new Character[] {'A','E','I','O','U','Y'};
There is another problem with the actual insertion, see Pankaj Singhal answer for a solution to that.
I have a string: LOAN,NEFT,TRAN. I want to substring the string based on getting a , during traversing the string. So I tried to first get a count for how many , are there. but not sure what function to user to get what I want. Also this should be dynamic, meaning I should be able to create as many substrings as required based on number of ,s. I tried the following code:
package try1;
public class StringTest {
public static void main(String[] args) {
String str="LOAN,NEFT,TRAN";
int strlen=str.length();
int count=0;
for(int i=0;i<strlen;i++)
{
if(str.contains("'"))
count++;
}
System.out.println(""+count);
for (int j=0;j<count;j++)
{
//code to create multiple substrings out of str
}
}
}
But I do not think contains() is the function I am looking for because value of count here is coming 0. What should I use?
Your code doesn't actually count the , characters because 1) contains doesn't take into account your loop variable 2) it's searching for ', not ,
Assuming you want to work at a low level rather than using high level functions like .split(), then I'd recommend the following.
for(char c : str.toCharArray()) {
if (c == ',') {
count++;
}
}
You can use split to get substrings directly:
String[] substrings = str.split(",");
Is this what you want as an output: (shown below)?
["LOAN", "NEFT", "TRAN"] // Array as an output
Or to just get the count of the splitting char, you can use the same line as above with this:
int count = substrings.length - 1;
For a school project I was asked to write a simple math parser in Java. The program works fine. So fine that I used NetBeans profiler tool to check the performance of the program. For that I made a loop of 1000 calls to the math parser of the following expression: "1-((x+1)+1)*2", where x was replaced by the current loop count. It took 262ms. The thing is, it took 50% of the time in the method splitFormula, which I shall present below:
private static void splitFormula(String formula){
partialFormula=new ArrayList<>();
for(String temp: formula.split("\\+|\\-|\\*|\\/"))
partialFormula.add(temp);
}
, where partialFormula is an ArrayList of Strings. To numerically evaluate an expression I need to call the splitFormula method various times so I really need to clear the contents of the partialFormula ArrayList - first line.
My question is: is there a faster way to split a string then add the partial strings to the an arraylist? Or is there some other method that can be used to split a string then use the substrings?
Regular expressions can slow things down (String#split uses regex). In general, if you want to write easy code, regex is good, but if you want fast code, see if there is another way. Try doing this without regex:
Edit: This should be a better method (keep track of the indices instead of append to a StringBuilder):
private static void splitFormula(String formula){
partialFormula.clear(); // since there is a method for this, why not use it?
int lastIndex = 0;
for (int index = 0; index < formula.length(); index++) {
char c = formula.charAt(index);
if (c == '-' || c == '+' || c == '*' || c == '/') {
partialFormula.add(formula.substring(lastIndex, index));
lastIndex = index + 1; //because if it were index, it would include the operator
}
}
partialFormula.add(formula.substring(lastIndex));
}
StringBuilder approach:
private static void splitFormula(String formula){
partialFormula.clear();
StringBuilder newStr = new StringBuilder();
for (int index = 0; index < formula.length(); index++) {
char c = formula.charAt(index);
if (c == '-' || c == '+' || c == '*' || c == '/') {
partialFormula.add(newStr.toString());
newStr.setLength(0);
} else {
newStr.append(c);
}
}
partialFormula.add(newStr.toString());
}
If we look at the source code for String#split, it becomes apparent why that is slower (from GrepCode):
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
It compiles a regex every time! Thus, we can see that another way of speeding up the code is to compile our regex first, then use the Pattern#split to split:
//In constructor, or as a static variable.
//This regex is a better form of yours.
Pattern operatorPattern = Pattern.compile("[-*+/]");
...
private static void splitFormula(String formula){
partialFormula.clear();
for(String temp: operatorPattern.split(formula)) {
partialFormula.add(temp);
}
}
You don't need a for loop. split returns an array, and you can create an ArrayList out of the array:
partialFormula = new ArrayList<>(Arrays.asList(formula.split("\\+|\\-|\\*|\\/")));
Whether this is significantly faster or not, I don't know.
Try pre-allocating the ArrayList beforehand so we do not have to pay for reallocation when the list grows. The number 20 below is just a placeholder. Pick a number that is a little bigger than the largest expression you expect.
partialFormula=new ArrayList<String>(20);
See this question for a discussion of what this might gain you.
This will create an arrayList of strings.
String a= "1234+af/d53";
char [] blah=a.toCharArray();
ArrayList<String> list=new ArrayList<String>();
for (int i = 0; i < blah.length; i++) {
list.add(Character.toString(blah[i]));
}