Filtering and Command Conditions
Conditions for filtering and executing commands
There are two application areas for the use of conditions:
- As a criterion for filtering data rows at input or output time, see ±filter.
- As a prerequisite for the execution of commands, see ±if/else.
All filtering and condition evaluating is field-based. It takes place line by line according to the general mode of operation of CSVfox, and is always based on the current data of the actual line.
Some filter examples
- +filter(#)>(3)
- Reads the current data row only if input line number is larger than 3.
I.e., the first three rows of the input file wil be omitted. - +filter[3]
- Reads and processes this data row only if the third column is not empty.
- -filter[Status]!={Locked}
- Outputs the current data row only if the column "Status" is not equal to the text "Locked".
- -filter[Fruit]={Apple}/{Pear}
- Outputs the current data row only if the text in column "Fruit" equals either "Apple" or "Pear".
- -filter(NumericExpression1)>(NumericExpression2)
- Outputs the current data row only if NumericExpression1 is larger than NumericExpression2.
"NumericExpression1" and "NumericExpression2" are calculated before comparison takes place.
Some conditional command examples
- -if["Not in Navigation"]=Yes//set[*]=1//else//set[*]=0
- If the field "Not in Navigation" contains the value "Yes", sets it to "1", otherwise to "0".
- -if[ThisField]={Expression}//set[ThatField]=Yesvalue//else//set[ThatField]=Novalue
- Inserts in column [ThatField] either "Yesvalue" or "Novalue", if column [ThisField] matches "Expression", else if not.
"Expression", "Yesvalue" and "Novalue" are resolved. For the conditions see below. - -if(NumericExpression1)>=(NumericExpression2)//set[Field]=1//else//set[Field]=2
- In column [Field], this inserts either "Yesvalue" or "Novalue" if "Expression1" is greater or equal to "Expression2", else if not.
"Expression1", "Expression2", "Yesvalue" and "Novalue" are resolved.
Condition Operands and Operators
Operands
An operand can be a single literal CSV field [Field], a numeric CSV field ([Field]), or a numeric expression a or formula (Expression), or a literal string or an expression {Expression}.
So there is always some kind of brackets around any left operand.
The right operand(s) do not require the {Expression} curly brackets.
Before evaluating the condition, all fields are replaced by their actual values, all formulas are calculated, and all expressions are resolved. For details, see also Expressions
In the following table, "{Opn}" stands for an operand of any kind, be it a single field, or of numeric, literal string, or expression type.
The left operand is always a single operand, while on the right side there may be more operands (see below).
{Op} = left operand
{Op1} = first right operand
{Op2} = another right operand ...
Available Condition Operators
Function | Operator | Alternative Operator |
String | Numeric | Number of Right Operands |
Syntax |
---|---|---|---|---|---|---|
{Op} not empty | ✓ | ✓ | 0 | {Op} | ||
{Op} empty | ! | n: | ✓ | ✓ | 0 | {Op}! |
{Op} equal {Op1} | = | e: | ✓ | ✓ | 1 * | {Op}={Op1} |
{Op} greater than {Op1} | > | g: | ✓ | ✓ | 1 * | {Op}>{Op1} |
{Op} lesser than {Op1} | < | l: | ✓ | ✓ | 1 * | {Op}<{Op1} |
{Op} greater or equal than {Op1} | >= | ✓ | ✓ | 1 * | {Op}>={Op1} | |
{Op} lesser or equal than {Op1} | <= | ✓ | ✓ | 1 * | {Op}<={Op1} | |
{Op} begins with {Op1} | <# | b: | ✓ | 1 * | {Op}<#{Op1} | |
{Op} finishes with {Op1} | #> | f: | ✓ | 1 * | {Op}#>{Op1} | |
{Op} contains {Op1} | <#> | c: | ✓ | 1 * | {Op}<#>{Op1} | |
{Op} regular matches {Op1} | @ | r: | ✓ | 1 * | {Op}@{Op1} | |
{Op} greater than {Op1}, and lesser than {Op2} |
<> | ✓ | 2 | {Op}<>{Op1}/{Op2} | ||
{Op} greater/equal to {Op1}, and lesser/equal to {Op2} |
<=> | ✓ | 2 | {Op}<=>{Op1}/{Op2} | ||
{Op} lesser than {Op1}, or greater than {Op2} |
>< | ✓ | 2 | {Op}><{Op1}/{Op2} | ||
{Op} lesser/equal to {Op1}, or greater/equal to {Op2} |
>=< | ✓ | 2 | {Op}>=<{Op1}/{Op2} |
* more operands can be used when concatenating them with delimiters, see below
As you see, there are two different operators available for each condition, the standard form and the alternative, alphabetical form.
Both operators do the same. While the standard form might be better readable and distinctive, using of the alphabetic version can be necessary e.g. when the commands are directly typed on the command line, and the command processor tends to misinterpret the comparison character, like the "<" and the ">".
Negation
All operators can also be used in a negated way.
Negations is expressed by prepending a "!" or a "n" before the operator.
So "=" or "e:" means "equal", while "!=" or "!e:" means "not equal" or "unequal" (as well as "n=" or "ne:", you can mix the variations).
In many cases, a negated operator is equivalent to another non-negated operator.
So, the negation of ">" (greater) is "!>" (not greater), which is equivalent to "<=" (lesser or equal).
But this does not apply to the literal operators "b:" (begins with), "c:" (contains), and "f:" (finishes with); here the negation "!b:" or "nb:" means "string does not begin with", "!c:" or "nc:" means "string does not contain", and "!f:" or "nf:" means "string does not end with".
Also the regular match "r:" can be negated with "nr:" or "!@" (or with a mix of both), which then means "string does not match the regular expression".
However, there is still an important difference when it comes to more than one operand on the right side.
Concatenated right operands
For all conditions that require one right operand, there can be used an operand list instead. An operand list consists of several operands concatenated with a single delimiter (generally a "/").
In this case, the condition will be evaluated with potentially each of those right operands, one after the other.
The following rules apply:
- In a plain, unnegated condition, multiple right operands are OR-ed. That means if at least one of the right operands lets the evaluation be true, the whole condition resolves to true.
- In a negated condition, multiple right operands are being AND-ed. That means that only if all of the right operands lets the evaluation be true, the whole condition resolves to true.
Note the difference and how you can use it for your purposes.
An example with the numerical filter condition "lesser than":
-filter([Nnn])<([A]) | Plain condition with one right operand: The numeric value of field [Nnn] is lesser than the numerical value of field [A]. |
-filter([Nnn])<([A])/([B])/([C]) | Plain condition with multiple right operands: Field [Nnn] is numerical lesser than field [A] or lesser than field [B] or lesser than field [C]. |
-filter[Nnn]!>=([A]) | Negated condition with one right operand: The numeric value of field [Nnn] is not greater or equal; i.e. ist is also lesser than field [A]. |
-filter([Nnn])!>=([A])/([B])/([C]) | Negated condition with multiple right operands: [Nnn] is numerical lesser than field [A] and also lesser than field [B] and also lesser than field [C]. |
Another example with the string filter condition "contains":
-filter[Xyz]c:abc | Plain condition with one right operand: Field [Xyz] contains the literal "abc". |
-filter[Xyz]c:abc/def/ghi | Plain condition with multiple right operands: Field [Xyz] contains "abc" or "def" or "ghi". |
-filter[Xyz]!c:abc/def/ghi | Negated condition with multiple right operands: Field [Xyz] does not contain "abc" and also not "def" and also not "ghi" (i.e., nor "abc" neither "def" neither "ghi"). |
filter/:[Xyz]!c:abc:def:ghi | The same as above, but with a changed separator (":" instead of "/"); while the ":" of the operator now looks like the separator ":", this is no real problem |
If there is an "empty" operand, you must place it first or last, so that the list of operands seems to start or end with a delimiter. Do not place it between delimiters, because this will be interpreted as a double delimiter which marks the start of next condition or command.
Also do not forget to "escape" all brackets that are not a grammatical part of a field identifier, formula or formatting expression, i.e. replacing all literal
Case-insensitive mode for strings
For case-insensitive comparisons of strings, the "i" mode can applied in two ways:
-filter[Field]={expression} | [Field] and {expression} are equal. |
-filter/i[Field]={expression} -filter[Field]i={expression} |
[Field] and {expression} are considered as equal, but the comparison is not case-sensitive. |
-filter[Field]!=[Another Field] | [Field] and [Another Field] are not equal. |
-filter/i[Field]!=[Another Field] -filterField]!i=[Another Field] |
[Field] and [Another Field] are not equal, comparison is not case-sensitive. |