Operator Scope of Action:
Operator First Added:
This operator tests whether pattern matches a whole discrete value string within the referenced list/set attribute. Unlike with string attributes matches using String.contains(), matches are always case-sensitive and cannot be overridden with $AgentCaseSensitive. The match gives a Boolean result.
Thus in default settings, List/Set.contains() is always:
- case-sensitive in an agent (unlike a String attribute $AgentCaseSensitive is ignored)
- case-sensitive in all other action code contexts
An always case-insensitive option is offered via List/Set.icontains() though it too cannot match below list item granularity.
pattern is one of:
- an action code expression (which includes just referencing a single attribute name')
- a quoted literal string (i.e. actual text). Important: do not omit the enclosing quotes. If omitted, Tinderbox will try to evaluate the string as an expression. Doing this may result in the expected result but this is actually a false positive. So, remember to enclose your literals in quotes.
The contains operator may also be used with both sets and lists, in which case it tests for set membership, i.e. matching to complete individual values rather than part of values. Thus:
are both true if $MyList contains "Monday;Tuesday;Friday". A match can use a attribute value as the pattern. Consider a single-value String-type attribute 'MyDay':
is true if the value of $MyDay for a given note is any of "Monday", "Tuesday or "Friday". Thus in an agent or find query, the pattern varies by the source value in the currently-tested note.
The chained list may also be a literal list:
If the pattern is found the function returns the matched list position (1-based). Formerly, .contains() returned true if the pattern was found.
Testing "does not contain"
Use a ! prefix to the query argument:
Use of parentheses after the !, around the query, can assist Tinderbox's parsing:
Testing lists values for partial matches
Used with care, there is a workaround by mimicking the way .replace() works with lists: see the section on regex. The trick is to use an on-the-fly list-to-string coercion allowing all list values to be regex-matched as if a single string. This is achieved by chaining List.format.contains. In order not to confuse the regex, the .format() join string should be a simple (ASCII) printable symbol that has no regex meaning. A hash (#) is a good example, though clearly this will not be good if the supplied list values include hash symbols! therefore you may need to alter the join symbol depending on your data.
Tinderbox stores a list of values, like ant/bee/cow/dog/eel, as a single semi-colon delimited string "
ant;bee;cow;dog;eel". So, for that list:
$MyList.format("#") returns "
It is possible to use a semi-colon join but it seems to tempt a parsing error, given that a semicolon is Tinderbox's list delimiter. The above result means that .contains() works as if doing a String.contains() test.
For the same data as above, these are effectively the same thing, albeit the first using a string literal:
In either case, .contains returns true, but would return false if 'bee' were removed. This is because the regex pattern only matches a double-e substring at the end of a value.
Until/unless Tinderbox's List.contains() directly supports substring matching within list values, the above offers a workaround.
Using .contains() to test individual value equivalence to a String
See == (equality) testing.