1

I'm learning regex and I have this fragment of code:

private static final String FILE_BEGINNING_PATTERN = "^(,Share %)";

public static void main(String[] args) {
    String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

    Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);
    if (beginningFileMatcher.find()) {
        System.out.println("Regex match!");
    }

    // find() method starts at the beginning of this matcher's region, or, if
    // a previous invocation of the method was successful and the matcher has
    // not since been reset, at the first character not matched by the previous
    // match.
    //

    int count = 0;
    while (beginningFileMatcher.find()) { // find not match, we need beginningFileMatcher.reset() but its not 
        // thread-safe.
        count++;
        System.out.println("COUNT ++++++++++++++ :" + count);
    }
}

try another way:

private static final String FILE_BEGINNING_PATTERN = "^(,Share %)";

public static void main(String[] args) {
    String s = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";
    Pattern beginningFilePattern = Pattern.compile(FILE_BEGINNING_PATTERN);
    Matcher matcher = beginningFilePattern.matcher(s);

    if (beginningFilePattern.matcher(s).find()) {
        System.out.println("Thread-safe regex match!.");
    }

    int countCount = 0;
    while (beginningFilePattern.matcher(s).find()) { //this cause infinite loop while matcher.find() done as 
        // expected result! Why?
        countCount++;
        System.out.println("COUNT ++++++++++++++ :" + countCount);
    }
}

I already comment on that problem in this snippet as above. Is there anyone who can explain why? Thank you so much!

12
  • If you need to check it once use if, why while? if (beginningFilePattern.matcher(s).find()) Commented Feb 24, 2020 at 8:12
  • unrelated: countCount should be initialized to 1if the first ifblock is true. Commented Feb 24, 2020 at 8:15
  • @WiktorStribiżew: this is code for testing. I need to count how many occurrences exist for some check condition in another place. Commented Feb 24, 2020 at 8:15
  • 1
    I don't understand your obsession with thread safety. Your code does not involve multithreading, so why worry about thread safety? Commented Feb 24, 2020 at 20:43
  • 1
    A simple java application like your example is always single-threaded. Only when you start using threads (either through the Thread class, through ExecutorService and related classes or by using Swing) will you have to worry about thread safety. But even then an object that you create and use within a single method is only used from a single thread. (Another thread could execute that same method at the same time, but that other thread would create and use it's own object.) Commented Mar 4, 2020 at 14:24

4 Answers 4

5

Problem is that you're creating a new Matcher instance every time in if condition and while loop blocks here:

if (beginningFilePattern.matcher(s).find()) {

and here:

while (beginningFilePattern.matcher(s).find())

By creating a new instance of Matcher you're losing previous state of that and starting match operation every time.

Also note removal of if condition before while loop to get the count right.

You may use this code to fix this:

String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);

// find() method starts at the beginning of this matcher's region, or, if
// a previous invocation of the method was successful and the matcher has
// not since been reset, at the first character not matched by the previous
// match.
//

int count = 0;
while (beginningFileMatcher.find()) { // find not match, we need beginningFileMatcher.reset() but its not 
    if (count == 0)
        System.out.println("Regex match!");
    // thread-safe.
    count++;
    System.out.println("COUNT ++++++++++++++ :" + count);
}

//try another way.
String s = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";
Pattern beginningFilePattern = Pattern.compile(FILE_BEGINNING_PATTERN);
Matcher matcher = beginningFilePattern.matcher(s);

int countCount = 0;
while (matcher.find()) { // make sure to use matcher object
    if (countCount == 0)
        System.out.println("Thread-safe regex match!");
    countCount++;
    System.out.println("COUNT ++++++++++++++ :" + countCount);
} 
Sign up to request clarification or add additional context in comments.

10 Comments

It not clear in the question but OP posted 2 version of his code. First one with a single matcher and second one with the infinite loop. Your solution is the same as OP's first one. Still it won't give him the correct result if the matcher matches only once
It does fix infinite loop problem that OP posted due to stated reason in ansewr.
@anubhava: Thank you, but is there another way to do this but still ensure thread-safe?
the do-while is a good idea but it will returns 1 if the pattern doesn't match
@anubhava: This worked fine, sir. But I'm still looking for a simplifier way. Suppose I have one CSV file with 1000 lines. I have to extract the name before the first comma in each line if that name matches my regex (E.g: ^(\w)\s(\w)(?=,)). What I want to do is replace all matched regex with empty String and also count how many lines matched in only one code block. Are you have any good ideas?
|
1

Each version of you code has a different issue.

For the version 2 (inifinite loop): You create the matcher in the loop. That means on each iteration, there will be a new matcher, starting at the begining of your String. So the call to find will always return the same result, if any.

Your first solution is what you need to do, create a matcher once and then use it by calling find in a loop.

The issue is that you call findin 2 different places. First in the if block, to see if there is any matches in your String, then in the loop.

What if the String contains only 1 matching result?

  • The result is returned in the ifblock
  • countCount is set to 0
  • The while loop try to find the next match but there is none
  • the code prints COUNT : 0

If you don't reset the matcher before looping, you need to count the result from the ifblock into your counter. Here is a solution with minimal changes:

final static String FILE_BEGINNING_PATTERN = "^(,Share %)";

public static void main(String[] args) {
    String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

    Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);

    int count = 0;
    if (beginningFileMatcher.find()) {
        System.out.println("Regex match!");
        count++; // already a match, increment the counter
    }

    while (beginningFileMatcher.find()) { 
        count++;
        System.out.println("COUNT ++++++++++++++ :" + count);
    }
}

Another way would be to remove the if block and use only the while loop.

Comments

0

You can Matcher reset()

Resets this matcher.
Resetting a matcher discards all of its explicit state information and sets its append position to zero. The matcher's region is set to the default region, which is its entire character sequence. The anchoring and transparency of this matcher's region boundaries are unaffected.

If you want it thread safe put it inside synchronize block

2 Comments

I'm don't know about synchronize block. I need to complete my task in today afternoon. Is there another way archive thread-safe?
0

I think the problem is that, when you call beginningFilePattern.matcher(s).find(), you are creating a new instance of the matcher inside the while condition. Each of those new matchers will check again from the beginning instead of trying to find the next occurrence. You should try to make your reset() call threat safe but keep the same matcher instance.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.