You can make sure that either tin or TIN using the character classes is not present:
^(?![a-zA-Z0-9]*(?:TIN|tin)[a-zA-Z0-9]*$).*(?:TIN|tin).*
(?i) Case insensitive match
^ Start of string
(?![a-zA-Z0-9]*(?:TIN|tin)[a-zA-Z0-9]*$) Assert that TIN or tin (as it is case insensitive, it does not matter for this example) does not occur between alpha numeric chars (no special characters so to say)
.*(?:TIN|tin).* Match the word in the line
You might add word boundaries \\b(?:TIN|tin)\\b for a more precise match.
Regex demo
Example for a single line:
String s = "CardTIN is 1111";
String[] wordsList = {"TIN","tin"};
String alt = "(?:" + String.join("|", wordsList) + ")";
String regex = "(?i)^(?![a-zA-Z0-9]*" + alt + "[a-zA-Z0-9]*$).*" + alt + ".*";
System.out.println(s.matches(regex));
Output
true
You can also join the list of words on | and then filter the list:
String strings[] = { "CardTIN is 1111", "Card-TIN:2222", "CardTINis3333", "Card@TIN@4444", "CardTIN@5555", "TINis9999", "test", "Card Tin is 1111" };
String[] wordsList = {"TIN","tin"};
String alt = "(?:" + String.join("|", wordsList) + ")";
String regex = "(?i)^(?![a-zA-Z0-9]*" + alt + "[a-zA-Z0-9]*$).*" + alt + ".*";
List<String> result = Arrays.stream(strings)
.filter(word -> word.matches(regex))
.collect(Collectors.toList());
for (String res : result)
System.out.println(res);
Output
CardTIN is 1111
Card-TIN:2222
Card@TIN@4444
CardTIN@5555
Card Tin is 1111
See a Java demo.
if (element.matches("(?i)CardTIN is \\d{4}|Card-TIN:\\d{4}|Card\\@TIN\\@\\d{4}|CardTIN\\@\\d{4}")) {.