USB
USB

Reputation: 6139

Matching a SubString in java

I have an input data stored in an arraylist. while iterating through the list the output is

Input ----------- [0 Overcast 1 High 2 Normal 3 Weak ]
Input ----------- [0 Rainy 1 Mild 2 High 3 Strong ]
Input ----------- [0 Rainy 1 Mild 2 Normal 3 Weak ]

and rule in another arraylist

Rule -----------[ 0 Overcast Yes, 0 Rainy 3 Strong No, 0 Rainy 3 Weak Yes, 0 Sunny 2 High No, 0 Sunny 2 Normal Yes]

I am expecting the output as

[0 Overcast 1 High 2 Normal 3 Weak Yes]
[0 Rainy 1 Mild 2 High 3 Strong No]
[0 Rainy 1 Mild 2 Normal 3 Weak Yes]

By looking into rule set I have to add label to input. For that I tried to match between input and rule set

for(String ruleSet : addRule){ //ruleset
 for(String lineSet : getLine){ //inputline
   if (lineSet.matches("(.*)"+ruleSet+"(.*)")) {
     System.out.println("got----------------"+lineSet+"***"+ruleSet);
     break;
   }
   else{
     System.out.println("Not found----------------"+lineSet+"***"+ruleSet);
   }
 }
}

But my result is like this

0 Overcast 1 High 2 Normal 3 Weak Yes is not matching with 0 Overcast Yes. Eventhough it is a subset.

Am I doing anything wrong.

Upvotes: 1

Views: 1213

Answers (1)

itsadok
itsadok

Reputation: 29342

If I understand correctly, you have two lists of String:

  1. getLine is a list of strings representing lines of input
  2. addRule is a list of strings representing rule sets.

Each rule contains several parts that need to match against the input line, and a result that should be used in case of a match.

(You seem to call this result "classpath", though that term has a very specific meaning in the context of Java).

So the line:

0 Overcast 1 High 2 Normal 3 Weak

Would match against the rule

0 Overcast

because it contains the substring "0 Overcast", but also against the rule:

0 Overcast 3 Weak

because the line contains the substrings "0 Overcast" and "3 Weak", even though the entire rule does not appear as a substring in the line.

I guess what you were looking for is a subset search, and maybe saw this answer and tried to use it, but doing a subset match between strings is complicated, and using a regular expression is possible, but a little trickier than what you tried, so I'd recommend trying to go with a simpler solution.

Specifically, just doing .matches("(.*)"+ruleSet+"(.*)") will not do what you want.

If I'm correct in my interpretation of your problem, let me know in the comments, and I'll try to help you find a solution.

Continued

So, assuming you have control of the rule set, I would probably make a Rule class that looks something like this:

public class Rule {
    public List<String> parts;
    public String result;

    public Rule(String result, String... parts) {
        this.parts = new ArrayList<>();
        for(String part : parts) {
            this.parts.add(part);
        }
        this.result = result;
    }

    public String match(String line) {
        for(String part : parts) {
            if (!line.contains(part)) return null;
        }
        return result;
    }
}

Notice how match is implemented: if any of the parts don't match, then the match fails.

(I used varargs for the constructor, but you can just pass a list if you want).

Then you can initialize the rule set like this:

List<Rule> ruleSet = new ArrayList<>();
ruleSet.add(new Rule("Yes", "0 Overcast"));
ruleSet.add(new Rule("No", "0 Rainy", "3 Strong"));
ruleSet.add(new Rule("Yes", "0 Rainy", "3 Weak"));
...

And when you loop against the rules, call match to get null if there's no match, or the result if there is a match.

for(Rule rule : ruleSet) {
    for(String line : getLine) {
       String result = rule.match(line);
       if (result != null) {
          ...

Alternatively, you can write the rules as regular expressions like this:

String rule = ".*0 Rainy.*3 Strong.*";
if(line.matches(rule)) {
    ...

But you should probably avoid regular expressions until you've had some time to learn about them. They're powerful tools, but have many caveats.


If you need to keep the rule set in a text file, then you're going to have to write a method to convert the lines into a Rule object, possibly as a different constructor. Here's one way to do it:

public class Rule {
    ...
    public Rule(String line) {
        this.parts = new ArrayList<>();
        String number = null;
        for (String s : line.split()) {
            if (s.equals("Yes") || s.equals("No")) {
                this.result = s;
                return;
            }
            if (number == null) {
                number = s;
            } else {
                this.parts.add(number + " " + s);
                number = null;
            }
        }
    }

Upvotes: 2

Related Questions