While(matcher.find()) - Error - Doesn't Work - java

I need a sort help
I don't know why it's jump in the while by matcher.find() when i'm have the string "3*3"
code:
public void delSin_Cos_Tan()
{
o = new ArrayList<>();
String aDate = "3*3";
Pattern datePattern = Pattern.compile("((sin|cos|tan|sinh|cosh|tanh|asin|acos|atan)\\((.+)\\))");
//Operat.Sin_Cos_Tan.Patter = ((sin|cos|tan|sinh|cosh|tanh|asin|acos|atan)\((.+)\))
Matcher matcher = datePattern.matcher(aDate);
Log.d(TAG,"Sin Startz");
Log.d(TAG,"Sin " + Aufgabe);
while (matcher.find());
{
Log.e(TAG,matcher.group(1)); // there is the Error, but withe the String "3*3" an i don't konw why it is jump inside the while
String Gesammt = matcher.group(1);
String TYP = matcher.group(2);
String Inklammer = matcher.group(3);
Log.d(TAG, String.valueOf("------------------------"));
Log.d(TAG, Gesammt);
Log.d(TAG, Inklammer);
Log.d(TAG, TYP);
Log.d(TAG, String.valueOf("------------------------"));
}
}
My completely Code: http://pastebin.com/jWN1ghfz

you got a ;after your while loop.
This is why your complete block will always get executed!
while (matcher.find()); should be while (matcher.find()) (whithout ;)
It's because
while (matcher.find());
{
//...
}
is the same as
while (matcher.find()){
;
}
{
//...
}

Related

how to delete up extra line breakers in string

I have got a text like this in my String s (which I have already read from txt.file)
trump;Donald Trump;trump#yahoo.eu
obama;Barack Obama;obama#google.com
bush;George Bush;bush#inbox.com
clinton,Bill Clinton;clinton#mail.com
Then I'm trying to cut off everything besides an e-mail address and print out on console
String f1[] = null;
f1=s.split("(.*?);");
for (int i=0;i<f1.length;i++) {
System.out.print(f1[i]);
}
and I have output like this:
trump#yahoo.eu
obama#google.com
bush#inbox.com
clinton#mail.com
How can I avoid such output, I mean how can I get output text without line breakers?
Try using below approach. I have read your file with Scanner as well as BufferedReader and in both cases, I don't get any line break. file.txt is the file that contains text and the logic of splitting remains the same as you did
public class CC {
public static void main(String[] args) throws IOException {
Scanner scan = new Scanner(new File("file.txt"));
while (scan.hasNext()) {
String f1[] = null;
f1 = scan.nextLine().split("(.*?);");
for (int i = 0; i < f1.length; i++) {
System.out.print(f1[i]);
}
}
scan.close();
BufferedReader br = new BufferedReader(new FileReader(new File("file.txt")));
String str = null;
while ((str = br.readLine()) != null) {
String f1[] = null;
f1 = str.split("(.*?);");
for (int i = 0; i < f1.length; i++) {
System.out.print(f1[i]);
}
}
br.close();
}
}
You may just replace all line breakers as shown in the below code:
String f1[] = null;
f1=s.split("(.*?);");
for (int i=0;i<f1.length;i++) {
System.out.print(f1[i].replaceAll("\r", "").replaceAll("\n", ""));
}
This will replace all of them with no space.
Instead of split, you might match an email like format by matching not a semicolon or a whitespace character one or more times using a negated character class [^\\s;]+ followed by an # and again matching not a semicolon or a whitespace character.
final String regex = "[^\\s;]+#[^\\s;]+";
final String string = "trump;Donald Trump;trump#yahoo.eu \n"
+ " obama;Barack Obama;obama#google.com \n"
+ " bush;George Bush;bush#inbox.com \n"
+ " clinton,Bill Clinton;clinton#mail.com";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
final List<String> matches = new ArrayList<String>();
while (matcher.find()) {
matches.add(matcher.group());
}
System.out.println(String.join("", matches));
[^\\s;]+#[^\\s;]+
Regex demo
Java demo
package com.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
String s = "trump;Donald Trump;trump#yahoo.eu "
+ "obama;Barack Obama;obama#google.com "
+ "bush;George Bush;bush#inbox.com "
+ "clinton;Bill Clinton;clinton#mail.com";
String spaceStrings[] = s.split("[\\s,;]+");
String output="";
for(String word:spaceStrings){
if(validate(word)){
output+=word;
}
}
System.out.println(output);
}
public static final Pattern VALID_EMAIL_ADDRESS_REGEX = Pattern.compile(
"^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
public static boolean validate(String emailStr) {
Matcher matcher = VALID_EMAIL_ADDRESS_REGEX.matcher(emailStr);
return matcher.find();
}
}
Just replace '\n' that may arrive at start and end.
write this way.
String f1[] = null;
f1=s.split("(.*?);");
for (int i=0;i<f1.length;i++) {
f1[i] = f1[i].replace("\n");
System.out.print(f1[i]);
}

how to fill an object based on a query param string?

I have strings like that:
//RULE countryname=Brazil&useryear<=2017&usermonth<=01&userdayofmonth<=15 200
I want to fill an object I created like this:
public class Rule {
public List<String> countries;
public LocalDateTime fromTime;
public LocalDateTime toTime;
I used regex, but I wondered if there is a more elegant way to do so?
#Test
public void testRegex() throws Exception {
Pattern pattern = Pattern.compile(".*?flag\\((\\d+)\\)=true(.*)");
Matcher matcher = pattern.matcher("bbbbbbflag(27)=true 300");
while (matcher.find()) {
System.out.println("group 1: " + matcher.group(1));
}
pattern = Pattern.compile("(.*?)countryname=([\\w-]+)(.*)");
matcher = pattern.matcher("countryname=brazil ");
while (matcher.find()) {
System.out.println("group 2: " + matcher.group(2));
}
pattern = Pattern.compile(".*?countryname=(.*+)&.*]");
matcher = pattern.matcher("countryname=brazil&bllllll");
while (matcher.find()) {
System.out.println("group 1: " + matcher.group(1));
}
pattern = Pattern.compile(".*?useryear<=(\\d+)&usermonth<=(\\d+)&userdayofmonth<=(\\d+)(.*)");
matcher = pattern.matcher("useryear<=2017&usermonth<=01&userdayofmonth<=15");
while (matcher.find()) {
System.out.println("group 1: " + matcher.group(1));
System.out.println("group 2: " + matcher.group(2));
System.out.println("group 3: " + matcher.group(3));
}
}
You could combine your patterns with | and then look for all the matches:
String s = "//RULE countryname=Brazil&useryear<=2017&usermonth<=01&userdayofmonth<=15 200\n";
Pattern p = Pattern.compile("((countryname)=([\\w-]+)|(useryear)<=(\\d+)|(usermonth)<=(\\d+)|(userdayofmonth)<=(\\d+))");
Matcher m = p.matcher(s);
while(m.find()){
String type = "";
String value = "";
boolean first = true;
for(int i = 2; i<=m.groupCount(); i++){
String group = m.group(i);
if(first && group != null){
type = group;
first = false;
}else if(group != null){
value = group;
break;
}
}
System.out.println("Type: " + type + " Value: " + value);
}
Outputs:
Type: countryname Value: Brazil
Type: useryear Value: 2017
Type: usermonth Value: 01
Type: userdayofmonth Value: 15
You can do it without a regex. Since your string is similar to an http query with parameters, we can parse it in a similar manner to an http query. Please try if this example can help you.
package gnu;
import java.util.*;
import java.util.stream.Collectors;
import java.util.AbstractMap.SimpleImmutableEntry;
import static java.util.stream.Collectors.toList;
public class Main {
public static void main(String[] strg) {
String str = "//RULE countryname=Brazil&useryear<=2017&usermonth<=01&userdayofmonth<=15 200";
str = str.substring(str.indexOf(" ")+1, str.lastIndexOf(" "));
try {
ParseParams parse = new ParseParams();
Map<String, List<String>> map = parse.parseParams(str);
map.entrySet().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
} catch (Throwable t) {
t.printStackTrace();
}
}
}
class ParseParams {
Map<String, List<String>> parseParams(String url) {
return Arrays.stream(url.split("&"))
.map(this::splitQueryParameter)
.collect(Collectors.groupingBy(SimpleImmutableEntry::getKey, LinkedHashMap::new, Collectors.mapping(Map.Entry::getValue, toList())));
}
private SimpleImmutableEntry<String, String> splitQueryParameter(String it) {
final int idx = it.indexOf("=");
String key = idx > 0 ? it.substring(0, idx) : it;
String value = idx > 0 && it.length() > idx + 1 ? it.substring(idx + 1) : null;
if (key.contains("<")) {
key = key.replace("<", "");
}
return new SimpleImmutableEntry<>(key, value);
}
}
Output
Key : countryname Value : [Brazil]
Key : useryear Value : [2017]
Key : usermonth Value : [01]
Key : userdayofmonth Value : [15]
Online demo.

examples on how to parse string in java

I have the following string that I need to parse/extract the '20000' out of it.
"where f_id = '20000' and (flag is true or flag is null)"
Any sugguestions on best way to do this?
Here's more code to help understand:
List<ReportDto> reportDtoList = new ArrayList<ReportDto>();
for (Report report : reportList) {
List<ReportDetailsDto> ReportDetailsDtoList = new ArrayList<ReportDetailsDto>();
ReportDto reportDto = new ReportDto();
reportDto.setReportId(report.getReportId());
reportDto.setReportName(report.getName());
Pattern p = Pattern.compile("=\\s'[0-9]+'");
String whereClause = report.getWhereClause();
Matcher m = p.matcher(whereClause);
Confused of what to do after this?
You can use this regex to extract a single nonegative integer from your String
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(text);
if (m.find()) {
System.out.println(m.group());
}
Or if you want to preserve the single quotes :
Pattern p = Pattern.compile("['0-9]+");
This will extract a pattern that includes '=' and a single space after that. It will print a String containing the number without '=' or the space. So if this matches you know there is a number after a '='
Pattern p = Pattern.compile("=\\s'[0-9]+");
Matcher m = p.matcher(text);
if (m.find()) {
System.out.println(m.group().substring(3));
}
EDIT
based on the code you added this is how it would look like
List<ReportDto> reportDtoList = new ArrayList<ReportDto>();
Pattern p = Pattern.compile("=\\s'[0-9]+");
for (Report report : reportList) {
List<ReportDetailsDto> ReportDetailsDtoList = new ArrayList<ReportDetailsDto>();
ReportDto reportDto = new ReportDto();
reportDto.setReportId(report.getReportId());
reportDto.setReportName(report.getName());
String whereClause = report.getWhereClause();
Matcher m = p.matcher(whereClause);
if (m.find()) {
String foundThis = m.group().substring(3);
// do something with foundThis
} else {
// didn't find a number or =
}
}
Try this:
Pattern p = Pattern.compile("-?\\d+");
String s = "your string here";
Matcher m = p.matcher(s);
List<String> extracted = new ArrayList<String>();
while (m.find()) {
extracted.add(m.group());
}
for floats and negatives
Pattern p = Pattern.compile("(-?\\d+)(\\.\\d+)?");
String s = "where f_id = '20000' 3.2 and (flag is true or flag is null)";
Matcher m = p.matcher(s);
List<String> extracted = new ArrayList<String>();
while (m.find()) {
extracted.add(m.group());
}
for (String g : extracted)
System.out.println(g);
prints out
20000
3.2

Java Regex And XML

I've been working on a weekend project, a simple, lightweight XML parser, just for fun, to learn more about Regexes. I've been able to get data in atributes and elements, but am having a hard time separating tags. This is what I have:
CharSequence inputStr = "<a>test</a>abc<b1>test2</b1>abc1";
String patternStr = openTag+"(.*?)"+closeTag;
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
StringBuffer buf = new StringBuffer();
boolean found = false;
while ((found = matcher.find())) {
String replaceStr = matcher.group();
matcher.appendReplacement(buf, "found tag (" + replaceStr + ")");
}
matcher.appendTail(buf);
String result = buf.toString();
System.out.println(result);
Output: found tag (<a>test</a>abc<b1>test2</b1>)abc1
I need to to end the 'found tag' at each tag, not the whole group. Any way I can have it do that? Thanks.
You can try with something as follows to get it working as you require;
int count = matcher.groupCount();
for(int i=0;i<count;i++)
{
String replaceStr = matcher.group(i);
matcher.appendReplacement(buf, "found tag (" + replaceStr + ")");
}

Improving the code that parses a Text File

Text File(First three lines are simple to read, next three lines starts with p)
ThreadSize:2
ExistingRange:1-1000
NewRange:5000-10000
p:55 - AutoRefreshStoreCategories Data:Previous UserLogged:true Attribute:1 Attribute:16 Attribute:2060
p:25 - CrossPromoEditItemRule Data:New UserLogged:false Attribute:1 Attribute:10107 Attribute:10108
p:20 - CrossPromoManageRules Data:Previous UserLogged:true Attribute:1 Attribute:10107 Attribute:10108
Below is the code I wrote to parse the above file and after parsing it I am setting the corresponding values using its Setter. I just wanted to know whether I can improve this code more in terms of parsing and other things also by using other way like using RegEx? My main goal is to parse it and set the corresponding values. Any feedback or suggestions will be highly appreciated.
private List<Command> commands;
private static int noOfThreads = 3;
private static int startRange = 1;
private static int endRange = 1000;
private static int newStartRange = 5000;
private static int newEndRange = 10000;
private BufferedReader br = null;
private String sCurrentLine = null;
private int distributeRange = 100;
private List<String> values = new ArrayList<String>();
private String commandName;
private static String data;
private static boolean userLogged;
private static List<Integer> attributeID = new ArrayList<Integer>();
try {
// Initialize the system
commands = new LinkedList<Command>();
br = new BufferedReader(new FileReader("S:\\Testing\\Test1.txt"));
while ((sCurrentLine = br.readLine()) != null) {
if(sCurrentLine.contains("ThreadSize")) {
noOfThreads = Integer.parseInt(sCurrentLine.split(":")[1]);
} else if(sCurrentLine.contains("ExistingRange")) {
startRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
endRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else if(sCurrentLine.contains("NewRange")) {
newStartRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[0]);
newEndRange = Integer.parseInt(sCurrentLine.split(":")[1].split("-")[1]);
} else {
allLines.add(Arrays.asList(sCurrentLine.split("\\s+")));
String key = sCurrentLine.split("-")[0].split(":")[1].trim();
String value = sCurrentLine.split("-")[1].trim();
values = Arrays.asList(sCurrentLine.split("-")[1].trim().split("\\s+"));
for(String s : values) {
if(s.contains("Data:")) {
data = s.split(":")[1];
} else if(s.contains("UserLogged:")) {
userLogged = Boolean.parseBoolean(s.split(":")[1]);
} else if(s.contains("Attribute:")) {
attributeID.add(Integer.parseInt(s.split(":")[1]));
} else {
commandName = s;
}
}
Command command = new Command();
command.setName(commandName);
command.setExecutionPercentage(Double.parseDouble(key));
command.setAttributeID(attributeID);
command.setDataCriteria(data);
command.setUserLogging(userLogged);
commands.add(command);
}
}
} catch(Exception e) {
System.out.println(e);
}
I think you should know what exactly you're expecting while using RegEx. http://java.sun.com/developer/technicalArticles/releases/1.4regex/ should be helpful.
To answer a comment:
p:55 - AutoRefreshStoreCategories Data:Previous UserLogged:true Attribute:1 Attribute:16 Attribute:2060
to parse above with regex (and 3 times Attribute:):
String parseLine = "p:55 - AutoRefreshStoreCategories Data:Previous UserLogged:true Attribute:1 Attribute:16 Attribute:2060";
Matcher m = Pattern
.compile(
"p:(\\d+)\\s-\\s(.*?)\\s+Data:(.*?)\\s+UserLogged:(.*?)\\s+Attribute:(\\d+)\\s+Attribute:(\\d+)\\s+Attribute:(\\d+)")
.matcher(parseLine);
if(m.find()) {
int p = Integer.parseInt(m.group(1));
String method = m.group(2);
String data = m.group(3);
boolean userLogged = Boolean.valueOf(m.group(4));
int at1 = Integer.parseInt(m.group(5));
int at2 = Integer.parseInt(m.group(6));
int at3 = Integer.parseInt(m.group(7));
System.out.println(p + " " + method + " " + data + " " + userLogged + " " + at1 + " " + at2 + " "
+ at3);
}
EDIT looking at your comment you still can use regex:
String parseLine = "p:55 - AutoRefreshStoreCategories Data:Previous UserLogged:true "
+ "Attribute:1 Attribute:16 Attribute:2060";
Matcher m = Pattern.compile("p:(\\d+)\\s-\\s(.*?)\\s+Data:(.*?)\\s+UserLogged:(.*?)").matcher(
parseLine);
if(m.find()) {
for(int i = 0; i < m.groupCount(); ++i) {
System.out.println(m.group(i + 1));
}
}
Matcher m2 = Pattern.compile("Attribute:(\\d+)").matcher(parseLine);
while(m2.find()) {
System.out.println("Attribute matched: " + m2.group(1));
}
But that depends if thre is no Attribute: names before "real" attributes (for example as method name - after p)
You can use the Scanner class. It has some helper methods to read text files
I would turn this inside out. Presently you are:
Scanning the line for a keyword: the entire line if it isn't found, which is the usual case as you have a number of keywords to process and they won't all be present on every line.
Scanning the entire line again for ':' and splitting it on all occurrences
Mostly parsing the part after ':' as an integer, or occasionally as a range.
So several complete scans of each line. Unless the file has zillions of lines this isn't a concern in itself but it demonstrates that you have got the processing back to front.

Categories