I have the following string
ford-focus-albany-ny-v12356-l12205
I'm trying to parse the last two sets of numbers out
12356 and 12205
I'm using the prefix letter to define the id type since the order of those int may very.
v = vehicle id "id length may very"
l = location id "id length may very"
I'd also like to add one may exist without the other. Example
ford-focus-v12356 or albany-ny-l12205
I'm really not sure what the best approach to splitting the string dynamically is, my initial thought was to find the last two - and then try to parse the ints from the prefix. Anybody have any suggestions or a possible example?
String str = "ford-focus-albany-ny-v12356-l12205";
String[] substrings = str.split("-");
for (String arg: substrings) {
if (arg.matches("v[0-9]*")) {
String v = arg.substring(1);
}
else if (arg.matches("l[0-9]*")) {
String l = arg.substring(1);
}
}
You can try it with regex expression and replace like this:
//this will give you 12356
"ford-focus-albany-ny-v12356-l12205".replaceAll( "(.*)(-v)([^-]*)(.*)", "$3" );
//this will give you 12205
"ford-focus-albany-ny-v12356-l12205".replaceAll( "(.*)(-l)([^-]*)(.*)", "$3" );
//this will also give you 12356
"ford-focus-v12356".replaceAll( "(.*)(-v)([^-]*)(.*)", "$3" );
//this will give you 12205
"albany-ny-l12205".replaceAll( "(.*)(-l)([^-]*)(.*)", "$3" );
You can match one or both of them with a simple pattern:
(?:-([vl])(\\d+))(?:-[vl](\\d+))?
The idea behind this pattern is simple: it matches and captures the initial marker -v or -l, followed by a sequence of digits, which are captured into capturing groups.
Pattern p = Pattern.compile("(?:-([vl])(\\d+))(?:-[vl](\\d+))?");
for(String s : new String[] {"ford-focus-albany-ny-v12356-l12205","ford-focus-albany-ny-l12205","ford-focus-albany-ny-v12356"}) {
Matcher m = p.matcher(s);
if (m.find()) {
if (m.group(1).equals("v")) {
System.out.println("verhicle="+m.group(2));
String loc = m.group(3);
if (loc != null) {
System.out.println("location="+loc);
} else {
System.out.println("No location");
}
} else {
System.out.println("No vehicle");
System.out.println("location="+m.group(2));
}
}
}
Here is a demo on ideone.
How about trying to split with String.split("-") and then use the Array returned like this:
String[] result = longString.split("-");
// Get the last number
String lastPrefix = result[result.lenght-1].subString(0, 1);
// Here check the prefix
// try to get number
int lastNumber;
try {
lastNumber = = Integer.parseInt(result[result.lenght-1].subString(1));
} catch (NumberFormatException e) {
// Do something with exception
}
// And now do similar with result.lenght-2
Related
I would like to be able to go through an inputted string and count the amount of times "good" is written and compare it to how many times "bad" is written. If the good and the bad match, then goodVbad==0 and it returns true. Otherwise it returns false.
The code worked fine when I was using if statements inside the for-loop, but when using the ternary operator it doesn't. While debugging, I realized that each time the for-loop moves onto the next element 'goodVbad' becomes zero again. Kind of stumped, would love some advice. Thanks!
public static boolean goodbadClean(String word) {
String [] wordS;
int goodVbad=0;
String good="good";
String bad="bad";
word=word.toLowerCase();
word=word.replaceAll(good, " good ");
word=word.replaceAll(bad, " bad ");
wordS=word.split(" ");
for(String i:wordS) {
goodVbad=i.equals(good)?goodVbad++
:i.equals(bad) ?goodVbad--
:goodVbad;
}
if(goodVbad==0) {
return true;
}
return false;
}
The problem is the postfix ++ operator returns the old value, which you are assigning the variable, then increments. ie
goodVBad = goodVBad++; // returns the old value, so does nothing
so you should use the prefixed ++ operator:
goodVBad = ++goodVBad; // increments first, returning the new value
But both of these are hard to read and brittle.
If you must use ternaries, change your code to:
goodVbad += i.equals(good) ? 1 : (i.equals(bad) ? -1 : 0);
However, nested ternaries are generally a style smell. I recommend instead:
if (i.equals(good)) {
goodVBad++;
} else if (i.equals(bad)) {
goodVBad--;
}
Assuming that the OP needs to count the frequency of a string pattern in a given string, then you could do something like this with Java 8 or older:
public class CountMatches {
public static void main(String[] args) {
String phrase1 = "goodbadbadgoodgoodbad"; // equal amount of good vs bad.
String phrase2 = "goodbadbadgoodgoodbadbad"; // more bad than good.
String phrase3 = "goodbadbadgoodgoodbadgood"; // more good than bad.
// create capturing groups for "good" and "bad"
String GOOD_REGEX = "(good)";
String BAD_REGEX = "(bad)";
Pattern gPattern = Pattern.compile(GOOD_REGEX);
Pattern bPattern = Pattern.compile(BAD_REGEX);
Matcher countGood = gPattern.matcher(phrase1);
Matcher countBad = bPattern.matcher(phrase1);
int count = 0;
while (countBad.find()) {
count--;
}
while (countGood.find()) {
count++;
}
System.out.println(count == 0);
}
}
With Java 9 or later:
public class CountMatches {
public static void main(String[] args) {
String phrase1 = "goodbadbadgoodgoodbad"; // equal amount of good vs bad.
String phrase2 = "goodbadbadgoodgoodbadbad"; // more bad than good.
String phrase3 = "goodbadbadgoodgoodbadgood"; // more good than bad.
String GOOD_REGEX = "(good)";
String BAD_REGEX = "(bad)";
Pattern gPattern = Pattern.compile(GOOD_REGEX);
Pattern bPattern = Pattern.compile(BAD_REGEX);
Matcher countGood = gPattern.matcher(phrase1);
Matcher countBad = bPattern.matcher(phrase1);
long cCount = countGood.results().count();
long bCount = countBad.results().count();
System.out.println(cCount - bCount == 0);
}
}
My assumption is based on this line of code word=word.replaceAll(good, " good ");. This tells me that the expected input is something similar to the phrase variables I used for my testing.
By the way, this solution should work even if the words "good" and/or "bad" are preceded or followed by spaces.
UPDATE: Integrated looping to evaluate all expressions against all phrases.
public static void main(String[] args) {
List<String> expressions = List.of("(good)", "(bad)");
List<String> phrases = List.of("goodbadbadgoodgoodbad", "goodbadbadgoodgoodbadbad", "goodbadbadgoodgoodbadgood", " good bad bad good good bad ");
for (String phrase : phrases) {
List<Long> itemCount = new ArrayList<>();
for (String regex : expressions) {
Pattern gPattern = Pattern.compile(regex);
Matcher matcher = gPattern.matcher(phrase);
long count = matcher.results().count();
System.out.println("Pattern \"" + regex + "\" appears " + count + (count == 1 ? " time" : " times"));
itemCount.add(count);
}
long count = itemCount.stream().reduce((value1, value2) -> value1 - value2).get();
System.out.println(count == 0);
}
}
This outputs:
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 3 times
true
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 4 times
false
Pattern "(good)" appears 4 times
Pattern "(bad)" appears 3 times
false
Pattern "(good)" appears 3 times
Pattern "(bad)" appears 3 times
true
I would like to compare and match exactly one word (characters and length) between two strings.
This is what I have:
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String lolo = scanner.nextLine();
if ( motCompare.toLowerCase().indexOf(lolo.toLowerCase()) != -1 ) {
System.out.println("Bingo !!!");
} else {
System.out.println("not found !!!");
}
If I type eagle:1,3:7;6 it should display Bingo !!!
If I type eagle:1,3 it still displays Bingo !!! which is wrong, it should display Not found.
If I type eagle:1,3:7;6 Basils,45673:ewwsk or eagle:1,3:7;6\nBasils,45673:ewwsk it should also display Not Found. Length of the typed word should be acknowledged between \n.
If I type Basils,45673:ewwsk, it displays bingo !!!
It looks like what you're wanting is an exact match, with the words being split by the newline character. With that assumption in mind, I would recommend splitting the string out into an array and then loading that into a HashSet like so:
boolean search(String wordDictionary, String search){
String[] options = wordDictionary.split("\n");
HashSet<String> searchSet = new HashSet<String>(Arrays.asList(options));
return searchSet.contains(search);
}
If the search function returns true, it has found whatever word you're searching for, if not, it hasn't.
Installing it in your code will look something like this:
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String lolo = scanner.nextLine();
if(search(wordCompare, lolo))
System.out.println("Bingo!!!");
else
System.out.println("Not found.");
(For the record, you'd probably be better off with more clear variable names)
As #Grey has already mentioned within his answer, since you have a newline tag (\n) between your phrases you can Split the String using the String.split() method into a String Array and then compare the elements of that Array for equality with what the User supplies.
The code below is just another example of how this can be done. It also allows for the option to Ignore Letter case:
boolean ignoreCase = false;
String userString = "Basils,45673:ewwsk";
String isInString = "'" + userString + "' Was Not Found !!!";
String wordCompare = "eagle:1,3:7;6\nBasils,45673:ewwsk\nlola:flower:1:2:b";
String[] tmp = wordCompare.split("\n");
for (int i = 0; i < tmp.length; i++) {
// Ternary used for whether or not to ignore letter case.
if (!ignoreCase ? tmp[i].trim().equals(userString) :
tmp[i].trim().equalsIgnoreCase(userString)) {
isInString = "Bingo !!!";
break;
}
}
System.out.println(isInString);
Thank you,
The thing is I am not allowed to use regular expression nor tables.
so basing on your suggestions I made this code :
motCompare.toLowerCase().indexOf(lolo.toLowerCase(), ' ' ) != -1 ||
motCompare.toLowerCase().lastIndexOf(lolo.toLowerCase(),' ' ) != -1)
as a condition for a do while loop.
Could you please confirm if it is correct ?
Thank you.
Well I'm almost finished with my world editor thanks to this great community, the only thing I need to know is how I can tell my read File code to process specific letters. When I hit enter on my keyboard I will write coordinates of a Vector3f to a text file, this Vector3f is the posistion of my active GameObject. My ProcessText method can read a text file and process the coordinates however he can only read ony type of format:
public void ProcessText()
{
String file_name = "C:/Users/Server/Desktop/textText.txt";
try
{
ProcessCoords file = new ProcessCoords(file_name);
String[] aryLines = file.OpenFile();
int i;
for (i = 0; i < aryLines.length; i++)
{
System.out.println(aryLines[i]);
if(aryLines[i].startsWith("makeGrass:")) {
String Arguments = aryLines[i].substring(aryLines[i].indexOf(":")+1, aryLines[i].length());
String[] ArgArray = Arguments.split(",");
this.makeGrass(Double.parseDouble(ArgArray[0]),
Double.parseDouble(ArgArray[1]),
Double.parseDouble(ArgArray[2]));
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
In the above example my ProcessText method can only process the coordinates if they are written like this:
makeGrass:x,y,z //for example makeGrass:5,1,9
But when I press enter and write the coordinates from what me my engine gives I'm getting a different format:
makeGrass:(x y z) //for example makeGrass:(3 1 4)
Now what I need to know is how I have to rewrite the code in my ProcessText method so it accounts for the other format that has brackets at the beginning and end and also with spaces to sepearta x from y and y from z instead of commas.
I really don't knwo where else I would find an answer to this question so I'd apreciate any help and explanation as to how this works.
Thanks a lot in advance!
You want to accept as many formats as possible?
Instead of splitting I would try to match, this is safer and doesn't need any pre- or post-processing of the input or the received substrings:
Pattern pattern = Pattern.compile("([0-9]+)"); // outside of method
long[] ArgArray = new long[3];
Matcher matcher = pattern.matcher(Arguments);
int i = 0;
while (matcher.find() && i < 3) {
ArgArray[i++] = Long.parseLong(matcher.group(1));
}
// there was a mistake if i < 3, otherwise you have 3 numbers in ArgArray
If you want to split, you could maybe try this: split("[^0-9]+")
To only match makeGrass:(x y z)
Pattern pattern = Pattern.compile("^makeGrass:\\(([0-9]+) ([0-9]+) ([0-9]+)\\)$");
Like this you can directly match the line and have the 3 numbers in groups 1 - 3 (as String) after calling find once, if (matcher.find()) will decide if it's a valid makeGrass line and if so it can be processed in the if.
if you can guarantee that there will not be any spaces in the makeGrass:x,y,z format and that there will not be any parenthesis in it either then you can use String.replaceAll()... Something like below:
myString = "makeGrass:(3 1 4)"
myString = myString.replaceAll("\(", ""); //replace ( with empty space
myString = myString.replaceAll("\)", ""); //replace ) with empty space
myString = myString.replaceAll(" ", ","); //replace spaces with commas
then you don't need to different methods to handle the two types of input. just format as shown above and pass both inputs to the same method
Going this way you will not need to split on certain chars and then rebuild the string to fit your format
Just split with the regular expression : [\s,]
Splits the String at places where there is either a white space or a ,.
And use this to get rid of any brackets if present :
Arguments = Arguments.replaceAll("\\(", "").replaceAll("\\)", "");
( and ) are part of regex notation. So, they need to be escaped with \ and \ being a Java notation, needs to be escaped with another\. Hence it becomes `"\(". And we have to replace the string and store it back to the String variable. Because Java is pass by value. Both the operations are done in the same line.
The modified code for the method is :
public void ProcessText() {
String file_name = "C:/Users/Server/Desktop/textText.txt";
public void ProcessText()
{
String file_name = "C:/Users/Server/Desktop/textText.txt";
try
{
ProcessCoords file = new ProcessCoords(file_name);
String[] aryLines = file.OpenFile();
int i;
for (i = 0; i < aryLines.length; i++)
{
System.out.println(aryLines[i]);
if(aryLines[i].startsWith("makeGrass:")) {
String Arguments = aryLines[i].substring(aryLines[i].indexOf(":")+1, aryLines[i].length());
Arguments = Arguments.replaceAll("\\(", "").replaceAll("\\)", "");
String[] ArgArray = Arguments.split("[\\s,]");
this.makeGrass(Double.parseDouble(ArgArray[0]),
Double.parseDouble(ArgArray[1]),
Double.parseDouble(ArgArray[2]));
}
}
} catch(IOException e) {
System.out.println(e.getMessage());
}
}
I'm trying to parse comma separated values that are enclosed in quotes using only standard Java libraries (I know this must be possible)
As an example file.txt contains a new line for each row of
"Foo","Bar","04042013","04102013","Stuff"
"Foo2","Bar2","04042013","04102013","Stuff2"
However when I parse the file with the code I've written so far:
import java.io.*;
import java.util.Arrays;
public class ReadCSV{
public static void main(String[] arg) throws Exception {
BufferedReader myFile = new BufferedReader(new FileReader("file.txt"));
String myRow = myFile.readLine();
while (myRow != null){
//split by comma separated quote enclosed values
//BUG - first and last values get an extra quote
String[] myArray = myRow.split("\",\""); //the problem
for (String item:myArray) { System.out.print(item + "\t"); }
System.out.println();
myRow = myFile.readLine();
}
myFile.close();
}
}
However the output is
"Foo Bar 04042013 04102013 Stuff"
"Foo2 Bar2 04042013 04102013 Stuff2"
Instead of
Foo Bar 04042013 04102013 Stuff
Foo2 Bar2 04042013 04102013 Stuff2
I know I went wrong on the Split but I'm not sure how to fix it.
Before doing split, just remove first double quote and last double quote in myRow variable using below line.
myRow = myRow.substring(1, myRow.length() - 1);
(UPDATE) Also check if myRow is not empty. Otherwise above code will cause exception. For example below code checks if myRow is not empty and then only removes double quotes from the string.
if (!myRow.isEmpty()) {
myRow = myRow.substring(1, myRow.length() - 1);
}
i think you will probably have to go for a stateful approach, basically like the code below (another state would be necessary if you want to allow escaping of quotes within a value):
import java.util.ArrayList;
import java.util.List;
public class CSV {
public static void main(String[] args) {
String s = "\"hello, i am\",\"a string\"";
String x = s;
List<String> l = new ArrayList<String>();
int state = 0;
while(x.length()>0) {
if(state == 0) {
if(x.indexOf("\"")>-1) {
x = x.substring(x.indexOf("\"")+1).trim();
state = 1;
} else {
break;
}
} else if(state == 1) {
if(x.indexOf("\"")>-1) {
String found = x.substring(0,x.indexOf("\""));
System.err.println("found: "+found);
l.add(found);
x = x.substring(x.indexOf("\"")+1).trim();
state = 0;
} else {
throw new RuntimeException("bad format");
}
} else if(state == 2) {
if(x.indexOf(",")>-1) {
x = x.substring(x.indexOf(",")+1).trim();
state = 0;
} else {
break;
}
}
}
for(String f : l) {
System.err.println(f);
}
}
}
Instead, you can use replaceAll, which, for me, looks more suitable for this task:
myRow = myRow.replaceAll("\"", "").replaceAll(","," ");
This will replace all the " with nothing (Will remove them), then it'll replace all , with space (You can increase the number of spaces of course).
The problem in above code snippet is that you are splitting the String based on ",".
on your Line start "foo"," and end ","stuff" the starting and ending quotes does not match with "," so there are not splitted.
so this definitely not a bug in java. in your case you need to handle that part yourself.
You have multiple options to do it. some of them can be like below.
1. If you are sure there will be always a starting " and ending " you can remove them from String before hand before splitting.
2. If the starting " and " are optional, you can first check it with startsWith endsWith and then remove if exists before splitting.
You can simply get the String delimitered by the comma and then delete the first and last '"'.
=)
hope thats helpfull
dont have much time :D
String s = "\"Foo\",\"Bar\",\"04042013\",\"04102013\",\"Stuff\"";
String[] bufferArray = new String[10];
String bufferString;
int i = 0;
System.out.println(s);
Scanner scanner = new Scanner(s);
scanner.useDelimiter(",");
while(scanner.hasNext()) {
bufferString = scanner.next();
bufferArray[i] = bufferString.subSequence(1, bufferString.length() - 1).toString();
i++;
}
System.out.println(bufferArray[0]);
System.out.println(bufferArray[1]);
System.out.println(bufferArray[2]);
This solution is less elegant than a String.split() oneliner. The advantage is that we avoid fragile string manipulation, ie. the use of String.substring(). The string must end with ," however.
This version handles spaces between delimiters. Delimiter characters within quotes are ignored as expected, as are escaped quotes (for example \").
String s = "\"F\\\",\\\"oo\" , \"B,ar\",\"04042013\",\"04102013\",\"St,u\\\"ff\"";
Pattern p = Pattern.compile("(.*?)\"\\s*,\\s*\"");
Matcher m = p.matcher(s + ",\""); // String must end with ,"
while (m.find()) {
String result = m.group(1);
System.out.println(result);
}
I wan to remove the last set of data from string using java.
For example I have a string like A,B,C, and I want to remove ,C, and want to get the out put value like A,B . How is it possible in java? Please help.
String start = "A,B,C,";
String result = start.subString(0, start.lastIndexOf(',', start.lastIndexOf(',') - 1));
Here is a fairly "robust" reg-exp solution:
Pattern p = Pattern.compile("((\\w,?)+),\\w+,?");
for (String test : new String[] {"A,B,C", "A,B", "A,B,C,",
"ABC,DEF,GHI,JKL"}) {
Matcher m = p.matcher(test);
if (m.matches())
System.out.println(m.group(1));
}
Output:
A,B
A
A,B
ABC,DEF,GHI
Since there may be a trailing comma, something like this (using org.apache.commons.lang.StringUtils):
ArrayList<String> list = new ArrayList(Arrays.asList(myString.split()));
list.remove(list.length-1);
myString = StringUtils.join(list, ",");
You can use String#lastIndexOf to find the index of the second-to-last comma, and then String#substring to extract just the part before it. Since your sample data ends with a ",", you'll need to use the version of String#lastIndexOf that accepts a starting point and have it skip the last character (e.g., feed in the string's length minus 1).
I wasn't going to post actual code on the theory better to teach a man to fish, but as everyone else is:
String data = "A,B,C,";
String shortened = data.substring(0, data.lastIndexOf(',', data.length() - 2));
You can use regex to do this
String start = "A,B,C,";
String result = start.replaceAll(",[^,]*,$", "");
System.out.println(result);
prints
A,B
This simply erases the the 'second last comma followed by data followed by last comma'
If full String.split() is not possible, the how about just scanning the string for comma and stop after reaching 2nd, without including it in final answer?
String start = "A,B";
StringBuilder result = new StringBuilder();
int count = 0;
for(char ch:start.toCharArray()) {
if(ch == ',') {
count++;
if(count==2) {
break;
}
}
result.append(ch);
}
System.out.println("Result = "+result.toString());
Simple trick, but should be efficient.
In case you want last set of data removed, irrespective of how much you want to read, then
start.substring(0, start.lastIndexOf(',', start.lastIndexOf(',')-1))
Another way to do this is using a StringTokenizer:
String input = "A,B,C,";
StringTokenizer tokenizer = new StringTokenizer(input, ",");
String output = new String();
int tokenCount = tokenizer.countTokens();
for (int i = 0; i < tokenCount - 1; i++) {
output += tokenizer.nextToken();
if (i < tokenCount - 1) {
output += ",";
}
}
public string RemoveLastSepratorFromString(string input)
{
string result = input;
if (result.Length > 1)
{
result = input.Remove(input.Length - 1, 1);
}
return result;
}
// use from above method
string test = "1,2,3,"
string strResult = RemoveLastSepratorFromString(test);
//output --> 1,2,3