I need to find credit card numbers in a chat transcript inside its before insert trigger and x them out. I have the following regex(s) first one works in online tools for long strings containing new lines and finds the patterns, second doesn't work in online tools for a long string containing new lines but works for a one line string.

String regex = '(\\d{4}[- ]){3}\\d{4}|\\d{16}';
String regex = '^(\\d{4}[- ]){3}\\d{4}|\\d{16}$';

Here's my simple method so far which isn't working for a string containing any of the variations such as,

  • 1234 1234 1234 1234

  • 1234-1234-1234-1234

  • 1234123412341234

     public static String findByRegexAndReplace(String stringToMatch, String replaceWith, String regex)
         String resultString;
         Pattern patternObj = Pattern.compile(regex);
         Matcher matcherObj = patternObj.matcher(stringToMatch);
         System.debug('matcherObj.matches()?'+ matcherObj.matches());
         if (matcherObj.matches()){
             resultString = matcherObj.replaceAll(replaceWith);
             for (Integer i=0; i<matcherObj.groupCount(); i++){
                 System.debug(i +': '+ matcherObj.group(i));
         return resultString;


matcherObj.matches() returns true only in this case, 1234-1234-1234-1234, but even then matcherObj.replaceAll(replaceWith) throws an exception like it does with every cases. Please help me understand what I'm doing wrong, if it's how I'm using the Matcher class methods or my regex isn't "Apex compatible"? Thanks!

  • 1
    Basically al regex's are "Apex compatible", but usually requires a deeper understanding of regex.
    – sfdcfox
    Mar 17, 2021 at 2:00

1 Answer 1


Matcher.matches() considers the entire string. What you're looking for is Matcher.find().

This will find every match, one at a time, until there are no more:

while(matcherObj.find()) {

However, if your intent is a regex search-and-replace, just use the relevant String method:

public static String findByRegexAndReplace(
  String stringToMatch, 
  String replaceWith, 
  String regex) {
    return stringToMatch.replaceAll(regex, replaceWith);

Obviously, it'd be more efficient at that point to just call the method directly.

  • Thanks for the clear answer, I'll try this out soon. Do you see any reason that the Live Chat Transcript body wouldn't work with this if I pass it to the method as the stringToMatch?
    – Bahman.A
    Mar 17, 2021 at 2:06
  • 1
    @Bahman.A changing matcherObj.matches() to matcherObj.find() would fix the if statement, but replaceAll works even if you don't call find first, and even if there are no matches. Still, I'd rather use the String method directly, as it literally does everything your method does in a single line of code. I think the error you got may stem from trying to call group() without first calling find().
    – sfdcfox
    Mar 17, 2021 at 2:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .