5

I am trying to find if a sentence contains at least 1 word from a different list of words.

I am able to do this like below code, however my concern goes that the "theSentence" is a string that is really huge (it comes from an API response), and I have multiple set of list of words to look for that are also quite big, so I am affraid, that using this type of loops will have a big effect in excecution time potentially leading me to a timeout, I am wondering what will be an alternative of this using?

Boolean wordFound = false;
List<String> words = new List<String>{'Word1', 'word2','....','word N'};
String theSentence = 'Hellow word';
for(String s:words){
    if(theSentence.contains(s)){
        wordFound = true;
        break;
    }
}

I am also using the classes Pattern and Matcher, but i still have to use a loop, so I am not sure if this is truly more efficient or not:

List<String> words = new List<String>{'Word1', 'word2','....','word N'}; 
String separator = '|';
Pattern p = Pattern.compile(String.join(words, separator));
Matcher m = p.matcher(attachment1.Body.toString());
boolean match = false;

while (m.find() == true) {         
    match = true;
    break;
}
3

The pattern, while technically more efficient, suffers from the 1,000,000 iteration limit, outlined in 000005024: Why do we get System.Exception: Regex too complicated error?.

In other words, if bodyString.length() * words.size() exceeds 1,000,000, you need to use contains. Otherwise, you can use the pattern. As a matter of practice, you could even use both methods, and determine which to use selectively based on the algorithm I provided here (n.b. I'm not actually sure if this calculation will work, so please adjust accordingly).

I'd probably recommend using contains if the number of words is any decent size, because it'll not throw the exception, which is actually a type of governor limit (the uncatchable kind of Exception).

To clear up a misconception, though, you wouldn't actually call find in a loop if you just wanted the first occurrence, so your actual pattern example could actually just be:

Boolean match = m.find();
  • Cool, you mentioned an algorithm but which one? Thank you – manza Dec 2 '16 at 1:38
  • 1
    @manza Use contains if you don't know how large the body is, or if there's a large number of words to check against. The governor limit is fatal and can't be caught. Use pattern if you know the file's size will never exceed the governor limit, because it's technically faster. There is no "one right answer," but if you have to pick just one, go with contains, because it's safer. – sfdcfox Dec 2 '16 at 3:52
1

One problem with contains or containsIgnoreCase, is that you can still hit a match on a subset string. For example, searching for LOW would hit any word that contains the string, like HOLLOW, BELOW, BLOW, LOWER, BLOWER, etc.

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.