3

For the given text obtained from a text area field:

Apex script unhandled exception by user/organization: xxx/xxx

Visualforce Page: /apex/pagename

caused by: System.NullPointerException: Attempt to de-reference a null >object

trace line 1

trace line 2

I want to match and capture

Visualforce Page: /apex/pagename

Note: This line can be anything but will always be a single line of text with followed by one or more \n then the line starting with caused by

I have tried the following regex at regex101 and it shows the FULL MATCH being "Visualforce Page: /apex/pagename "

In salesforce I am using the following pattern

(?im).*(?=\\n*caused by.*)

Which in regex101 grabs the first non empty line prior to the "caused by"

enter image description here

Now when I run the following code I get a true value debugged

System.debug(
     Pattern.compile('(?m).*(?=\\n*caused by.*)')
        .matcher(t).find()
);

But I cannot seem to get the actual text of the match.....

I am using the following code and get the following debug

System.debug(t);

Pattern p = Pattern.compile('(?im).*(?=\\n*caused by.*)');

Matcher m = p.matcher(t);

while(m.find()){
    System.debug(m.groupCount());
    System.debug(m.start());
    System.debug(m.end());
    System.debug(m.group(0));
}

enter image description here

Note: I also tried the following pattern with same results (?im)(.*)(?=\\n*caused by)

Update -- Still not working but

I added a check for charAt to see what group 1 was returning when I used the pattern: (?im)(.*)(?=\\n*caused by.*)

doing a m.group(1).length gets 0

so I changed the pattern to (?im).*[^\\n](?=\\n*caused by.*)

doing a m.group(0).length gets 0 for the first find and 1 for the second find. The second find is char(13)

System.debug(m.groupCount());
String x = m.group(0);
System.debug(x);
System.debug(x.length());
System.debug(x.charAt(0));

enter image description here

trying to do the pattern (?im).*[^\\r\\n](?=\\n*caused by.*)results in no matches...

When copied and pasted into regex101 it works fine but seems apex is having issues. I cannot seem to get anything but the CR or LF back and when I try to exclude both I get no matches

BUT If I do this before the matching process it works fine:

t = t.replaceAll('\\r','');

I am not the best at regex so I cannot seem to get it to exclude the \r as when I include [^\\r\\n] when not replacing the \r I get no matches

enter image description here

I am not the best at regex and pattern and matcher so any help on getting the matched text would be great

  • 1
    I've run your code myself in an anonymous apex window, and I get debug lines stating matches from 63-95, 95-95, 96-96, and 97-97. The differences are due to some extra newlines/whitespace (probably), but you should be getting your target substring by just executing m.find(); and then m.group(). Are you using the Salesforce cli to execute an anonymous block? What happens if you execute via anonymous window from a dev console? – Derek F Mar 16 at 13:45
  • I am executing the whole thing via Exec Anon. Based on your deleted answer I now know it is the CHR(13) Carriage Return that is being returned by group 1 when I group the (.*). If I add \\r to the look forward I get no matches. Still stuck but I will update my question with the findings... – Eric Mar 16 at 13:49
  • @DerekF - Updated my answer. It seems it is returning either chr(10) if I do not exclude \\n or chr(13) if I do exclude \\n. Trying to exclude both [^\\r\\n] results in no match. Yet the operation works in all the regex testers I have found..... – Eric Mar 16 at 14:05
  • doing a replace('\r','') on the queried string makes it work but I would prefer to be able to do this in regex rather than another line of code to make it work....maybe its not possible. – Eric Mar 16 at 14:12
3

Ok, so you've got carriage returns in the mix here too.

Newlines and carriage returns aren't matched by the wildcard . by default. You can add the 's' flag to your regex options to include newline characters in ., but that'd make it more difficult to isolate your substring match to just the second line.

Instead, you can use a capturing group inside of your lookahead to check for 0 or more \r or \n

String t = 'Apex script unhandled exception by user/organization: xxx/xxx\r\n\r\nVisualforce Page: /apex/pagename\r\n\r\ncaused by: System.NullPointerException: Attempt to de-reference a null >object\r\n\r\ntrace line 1\r\n\r\ntrace line 2';

System.debug(t);

Pattern p = Pattern.compile('(?im).*(?=(\\r|\\n)*caused by.*)');

Matcher m = p.matcher(t);

while(m.find()){
    System.debug(m.start());
    System.debug(m.end());
    System.debug(m.group());
}

resulting debug log

  • 1
    Ahh the | is what did it.....I also added it to the exclusion for the match and got it down to only the matched line using the pattern '(?im).*[^\\r|\\n](?=(\\r|\\n)*caused by.*)'); - Thank you for helping me past it. Had me stumped with all the regex testers working from a direct copy and paste of the text area field without having to do all the CR stuff – Eric Mar 16 at 15:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.