Java String.matches("regex") - java

I don't know regex very well. I am trying to find strings that start with digits 2,3,5 or 7, are 1,3,7 or 9 throughout the middle, and end with 3 or 7.
My attempt was [2357][1379]*[37]. It does not work. I'd appreciate a correction. Remember that this is meant for the Java String.matches() function. Thanks in advance
for (int s = 0; s < primes.size(); ++s) {
String p = primes.get(s);
if (!p.matches([REGEX GOES HERE])) {
System.out.println(p);
primes.remove(s);
}
}

The standard method of iterating over a collection you remove from in the loop is to iterate downwards that way removals don't affect the index of subsequent elements:
for (int s = primes.size() - 1; s >= 0; s--) {
String p = primes.get(s);
if (!p.matches("[2357][1379]*[37]")) {
System.out.println(p);
primes.remove(s);
}
}
No need now to worry about implications of removing elements.

The following code "works" just fine:
List<String> primes = new ArrayList<String>();
primes.add("1");
primes.add("2");
primes.add("7");
primes.add("23");
primes.add("213");
primes.add("243");
primes.add("2113");
primes.add("2193");
for (int s = 0; s < primes.size(); ++s) {
String p = primes.get(s);
if (!p.matches("[2357][1379]*[37]")) {
System.out.println(p);
primes.remove(s);
}
}
It outputs:
1
7
243
You may have expected it to output:
1
2
7
243
However, the primes.remove(s) is messing up your loop. That can't really be the intent of your design. (But who knows?!) The following is one of many solutions to avoid messing up your loop:
for (String prime : new ArrayList<String>(primes)) {
if (!prime.matches("[2357][1379]*[37]")) {
System.out.println(prime);
primes.remove(prime);
}
}

Hi I am not sure I am mistaken .. but i dont see anything wrong in your initial pattern for example
String aa = "[2357][1379]*[37]";
String bb = "2977313";
boolean matches = Pattern.matches(aa, bb);
System.out.println("1) "+matches);
I started with no 2 and then ended with no 3 and added 1379 in between and it works as expected. Please correct me if i am wrong

Your regex works well. However, remove shifts any subsequent elements to the left, so the String ordinarily at position s + 1 is moved to s, so the next element to check is at position s instead of s + 1. Fix:
for (int s = 0; s < primes.size();) {
String p = primes.get(s);
if (!p.matches("[2357][1379]*[37]")) {
System.out.println(p);
primes.remove(s);
} else
++s;
}

Related

Cut out different elements from a string and put them into a list

Here's updated code. For those following along the question edits contains the original question.
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0);
index != -1;
index = input.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
System.out.println(ListStringIN.length());
indexOUT=input.indexOf(ListStringOUT, occurences - 1);
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
As you can see, I gave me out the index numbers
My code works well with only one Element
But when I write something like this: %%%%ONE++++ %%%%TWO++++
There's this exception:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 16, end 7, length 23
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3410)
at java.base/java.lang.String.substring(String.java:1883)
at com.DMMS.Main.identify(Main.java:81)
And I found out that the indexIN changes in the Start of the second String but not the indexOUT
I couldn't find out why
When you look at your code you can notice: in the first loop that counts the number of occurrences, your code "knows" that it has to use that version of indexOf() that relies on offsets within the search strings.
In other words: you know that you have to search after previous "hits" when walking through your string.
But your second loop, the one that has to extract the actual things, there you are using indexOf() without that extra offset parameter. Therefore you keep "copying out" the same part repeatedly.
Thus: "simply" apply the same logic from loop 1 for loop 2!
Beyond that:
you don't need two loops for that. Counting occurrences and "copying out" the matching code ... can be done in one loop
and honestly: rewrite that first loop. This code is almost incomprehensible for human beings. A reader would have to sit down and read this 10, 20 times, and then run it in a debugger to understand what it is doing
I dit it!
Heres the code:
.........................
static String ListStringIN = "%%%%";
static String ListStringOUT = "++++";
........................
else if (input.contains(ListStringIN) && input.contains(ListStringOUT)) {
System.out.println("Identifiziere Liste...");
String searchString = ListStringIN;
int occurences = 0;
boolean eagerMatching = false;
if (0 != searchString.length()) {
for (int index = input.indexOf(searchString, 0); index != -1; index = input
.indexOf(searchString, eagerMatching ? index + 1 : index + searchString.length())) {
occurences++;
System.out.println(occurences);
indexIN=input.indexOf(ListStringIN, occurences - 1) + ListStringIN.length();
System.out.println(indexIN);
//indexOUT=input.indexOf(ListStringOUT, occurences);
//indexOUT=input.indexOf(ListStringOUT, occurences - 1);
indexOUT = input.indexOf(ListStringOUT, eagerMatching ? index + 1 : index + ListStringOUT.length());
System.out.println(indexOUT);
Lresult.add(input.substring(indexIN, indexOUT));
System.out.println();
}
}
//for (int i = 0; i <occurences; i ++) {
// Lresult.add(input.substring(input.indexOf(ListStringIN, 0) + ListStringIN.length(), input.indexOf(ListStringOUT)));
//}
result = Lresult.toString();
return result;
}
I hope this is useful for other people
#GhostCat Thanks for your advices!

Appium: How to iterate over a listview of unknown length?

I have a list view with a hierarchy I theoretically have no knowledge of. I am attempting to accept a String array and create MobileElements for each string in it, but due to the way I've automated (PageFactory) defining my elements via annotations, they cannot use variables. I also don't know that it's valid or proper to define my annotations inside a method.
The code I've written, which obviously does not compile follows:
public void selectLocation(String[] location) {
List<MobileElement> locationsList = new ArrayList<>();
for(int i = 0; i < location.length; i++) {
#iOSFindBy(accessibility = location[i])
#AndroidFindBy(xpath = "//android.widget.TextView[#text='" + location[i] + "']")
locationsList.add(i);
}
for (int i = 0; i < location.length; i++) {
locationsList.get(i).click();
}
}
I'm assuming the proper way to do this is wholly different from the way I've implemented.
My list hierarchy is similar to the following; my end point could vary depending on the branch I go down:
Continent 1
City 1
Room 1
Room 2
City 2
Building 1
Room 1
Room 2
Building 2
Room 1
Room 2
I now look for a matching element. If I don't find it, I swipe further into the list. If the element doesn't exist I obviously run into problems, but not really an issue in my case since that’d be a failing test.
while (!driver.findElementById(currentLocation).isDisplayed()) {
driver.swipe(startX, startY, startX, endY, 100);
}
driver.findElementById(currentLocation).click();
Yes, I also realize .swipe() is deprecated, but it still works for me and I'd rather not rewrite all my code with TouchActions until necessary.
I ended up using the "FindsBys" functions to create an array of all matching elements. I then loop through those elements looking for a match to one of my strings.
#AndroidFindBys({#AndroidFindBy(xpath = "//android.widget.TextView")})
#iOSFindBys({#iOSFindBy(xpath = "//XCUIElementTypeStaticText")})
private List<MobileElement> locationsList;
...
public void selectLocation(String[] location)
{
for(int i = 0; i < locationsList.size(); i++)
for(int p = 0; p < location.length; p++) {
if (locationsList.get(i).getText().equals(location[p])) {
locationsList.get(i).click();
}
}
}
It's not foolproof (if you have duplicate strings at different levels of your hierarchy you may run into issues), but it works for my use-case and should be able to guide anyone looking for a stronger solution.
You can just loop over the elements themselves.
....
for(MobileElement location: locationsList) {
for(int p = 0; p < location.length; p++) {
if (location.getText().equals(location[p])) {
location.click();
}
}
}

How can I most efficiently execute this recursive/iterative CPU intensive android task?

Some Background Info: I have made a program that given an arraylist of letters, and an array of integers finds all the combinations of words that can exist inside this arraylist where the words length is one of the integers in the int array (wordSizes).
i.e. given h, o, p, n, c, i, e, t, k and the integers 5 and 4, the solution would be:
phone tick.
My problem right now:
Inputs usually are about 25 characters and the output should usually return 5 word combinations.
I originally made this a console application for dekstop, and runtimes are generally less than 1 minute.
I decided to port it to android and runtimes reach over 35 minutes. I am quite a beginner and not sure about how to run a CPU intensive task on Android.
public void findWordsLimited(ArrayList<Character> letters) {
for (String s1 : first2s) {
for (String s2 : possibleSeconds) {
boolean t = true;
String s1s2 = s1.concat(s2);
ArrayList<Character> tempLetters = new ArrayList<Character>(letters);
for (int i = 0; i < s1s2.length(); i++) {
if (tempLetters.contains(s1s2.charAt(i)))
tempLetters.remove(Character.valueOf(s1s2.charAt(i)));
else
t = false;
}
if (t) {
helperFindWordsL(tempLetters, s1 + " " + s2, 2);
}
}
}
}
public void helperFindWordsL(ArrayList<Character> letters, String prefix , int index) {
boolean r;
if (letters.size() <= 1) {
output += "Success : " + prefix + "\n";
Log.i(TAG, prefix);
}
else if (index < wordSizes.size()){
for (String s : lastCheck) {
if (s.length() == wordSizes.get(index)) {
ArrayList<Character> templetters = new ArrayList<Character>(letters);
r = true;
for (int j = 0; j < s.length(); j++) {
if (templetters.contains(s.charAt(j)))
templetters.remove(Character.valueOf(s.charAt(j)));
else {
r = false;
templetters = new ArrayList<Character>(letters);
}
}
if (r)
helperFindWordsL(templetters, prefix + " " + s, index + 1);
}
}
}
}
I am not too concerned about the algorithm, as this might be confusing because it is part of a bigger project to solve a word game puzzle.
A few questions:
How would I get a CPU intensive task like this finished fastest?
Right now I call the method findWordsLimited() from my MainActivity. On my desktop app (where it says output += Success... in HelperFindWordsL) I would print all solutions to the console, but right now I have made it so that the method adds to and in the end returns a giant string (String output) back to the MainActivity, with all solutions and that String is put inside of a TextView. Is that an inefficient way to display the data? If so, could you please help explain a better way?
Should I be running this as a backgroud/foreground process or thread instead of just calling it from the MainActivity?
How can i get runtimes on my android that are currently 20x slower than my desktop faster?
Try to replace recursion with cycles, and use arrays instead of lists, to avoid inserts etc, direct access to array members is much faster. Pay main attention to the most inner loop which uses templetters.contains(s.charAt(j)), optimization of this part of code will give main effect.
You may add break; after t = false;
String s1s2 = s1.concat(s2); - it's not good to create a new String object for such case - it makes unnecessary work for GC. I would replace it with 2 cycles through s1 then s2
You could use 'letters' instead of ArrayList<Character> tempLetters = new ArrayList<Character>(letters);, just marking some items there as deleted. No need to create local clones.

For Loop is performing slow

Please have a look at the following code
//Devide the has into set of 3 pieces
private void devideHash(String str)
{
int lastIndex = 0;
for(int i=0;i<=str.length();i=i+3)
{
lastIndex = i;
try
{
String stringPiece = str.substring(i, i+3);
// pw.println(stringPiece);
hashSet.add(stringPiece);
}
catch(Exception arr)
{
String stringPiece = str.substring(lastIndex, str.length());
// pw.println(stringPiece);
hashSet.add(stringPiece);
}
}
}
The above method receives String like abcdefgjijklmnop as the parameter. Inside the method, its job is to divide this sets of 3 letters. So when the operation is completed, the hashset will have pieces like abc def ghi jkl mno p
But the problem is that if the input String is big, then this loop takes noticeable amount of time to complete. Is there any way I can use to speed this process?
As an option, you could replace all your code with this line:
private void divideHash(String str) {
hashSet.addAll(Arrays.asList(str.split("(?<=\\G...)")));
}
Which will perform well.
Here's some test code:
String str = "abcdefghijklmnop";
hashSet.addAll(Arrays.asList(str.split("(?<=\\G...)")));
System.out.println(hashSet);
Output:
[jkl, abc, ghi, def, mno, p]
There is nothing we can really tell unless you tell us what the "noticeable large amount" is, and what is the expected time. It is recommended that you start a profiler to find what logic takes most time.
Some recommendations I can give from briefly reading your code is:
If the result Set is going to be huge, it will involve lots of resize and rehashing when your HashSet resize. It is recommended you first allocate required size. e.g.
HashSet hashSet = new HashSet<String>(input.size() / 3 + 1, 1.0);
This will save you lots of time for unnecessary rehashing
Never use exception to control your program flow.
Why not simply do:
int i = 0;
for (int i = 0; i < input.size(); i += 3) {
if (i + 3 > input.size()) {
// substring from i to end
} else {
// subtring from i to i+3
}
}

Line Not Found on while loop?

I've been trying to get this to work for a while. I'm putting in three parallel empty arrays and it errors out saying that there is no line found. It ONLY works when I change the while statement to the number of elements. I am trying to make arrays that are the size of 15, but only fill the first ten array portions.
Sorry if it sounds complicated, but basically I'm trying to say that the size of the array is 15, I only have 10 things to enter in the array, and the rest of them should be blank.
while (text.hasNext() && c < nameArray.length) {
nameArray[count] = text.nextLine();
intArray[count] = text.nextDouble();
doubleArray[count] = text.nextInt();
text.nextLine();
c++;
}
This does not work.
while (text.hasNext() && c < 9) {
nameArray[count] = text.nextLine();
intArray[count] = text.nextDouble();
doubleArray[count] = text.nextInt();
text.nextLine();
c++;
}
This does.
Your read the file TWICE within a single loop. Remove the 2nd read:
fileText.nextLine();
Of course it doesn't work. If you need to cycle to the max between fileText length and gameArray length, you should use or instead of and and use an if in the loop.
Try something like this:
while (fileText.hasNext() || count < gameArray.length) {
if (!fileText.hasNext()) {
gameArray[count] = "";
priceArray[count] = 0;
stockArray[count] = 0;
} else {
gameArray[count] = fileText.nextLine();
priceArray[count] = fileText.nextDouble();
stockArray[count] = fileText.nextInt();
fileText.nextLine();
}
count++;
}
Your issue is not with the length of the array but with fileTest.nextLine(). After a certain point there is no nextLine() available. It works for the 1st 9 times but I guess all the lines are exhausted before you reach array.length. I would suggest just one condition in your while loop:
while(fileText.hasNext()) {
}
This way you would fill in only the amount actually present.
Add another check with the second fileText.nextLine() to ensure that there is a line to read.
while (fileText.hasNext() && count < gameArray.length) {
gameArray[count] = fileText.nextLine();
priceArray[count] = fileText.nextDouble();
stockArray[count] = fileText.nextInt();
if ( fileText.hasNext() )
fileText.nextLine();
count++;
}
In the first version of your code, your try to read input 15 times, but it is entered only 10 times. So the scanner tries to read a new line but it doesn't exist.

Categories

Resources