01469: Extend ConditionalMarkup with "less" and "greater" operators
Description: ConditionalMarkup provides an "equal" operator.
This is a feature request to add a "greater" and a "less" operator to the core (or ">" and "<"). Like "equal" these would work on numbers and strings.
For completeness "equalgreater" and "equalless" could also be added (or ">=" and "<=").
While recipes do provide so DIY options these seem like basic functionality and would provide consistent markup common to all PmWikis in the core.
See also
- ConditionalExtensions A Conditional Markup extension for PmWiki 2.x
- ConditionalMarkupSamples List of default and custom conditional markup definitions
- 01209 Add more markup expressions to the core
simon September 08, 2021, at 02:39 AM
Here is a possible implementation, possibly Core candidate:
$Conditions['cmp'] = 'CondCmp($condparm)'; function CondCmp($condparm) { global $CondCmpFoldFunction, $StrFoldFunction; $fn = IsEnabled($CondCmpFoldFunction, $StrFoldFunction); $args = ParseArgs($fn($condparm), '()'); $params = $args['']; if(count($params)<3) return false; while(count($params)>=3) { $r = strnatcmp($params[0], $params[2]); $op = htmlspecialchars_decode($params[1]); # Not an operator if(! preg_match('/^([=<>]=?|[<][>])$/', $op)) return false; if($r == 0 && $op == '<>') return false; if($r != 0 && ($op == '=' || $op == '==')) return false; if($r < 0 && ($op == '>' || $op == '>=')) return false; if($r > 0 && ($op == '<' || $op == '<=')) return false; $params = array_slice($params, 2); } return true; }
Use it like this:
(:if cmp "a" <= "b":) %green%TRUE(:else:)%red%FALSE(:if:) ---- (:if cmp "a9" < "a10":) %green%TRUE(:else:)%red%FALSE(:if:) ---- (:if cmp "a9" < "a20" <= "b1":) %green%TRUE(:else:)%red%FALSE(:if:) | TRUE
TRUE
TRUE
|
This is enabled on this page, you can test it.
Notes:
- It starts with
(:if cmp ... :)
- Operators can be among
= or ==, <, >, <=, >=, <>
. Operators cannot be=<, =>
. - Quotes are highly recommended, especially if using page variables.
- Multiple comparisons are possible in the same expression, like the 3rd example above, checking if one element is between 2 values. In this case, the elements are compared left to right, and all need to be true to return true.
- The comparison uses the natural sorting algorithm so "a9" is less than "a10" with the elements folded to lowercase, so "A15" and "a15" would be equal.
- In fact, $StrFoldFunction is used to fold the strings to lowercase, and can be overridden by defining $CondCmpFoldFunction. For example, to have case-sensitive comparison, one could define
$CondCmpFoldFunction = 'IsEnabled';
.
Let me know if this works for you, and in what situations. I don't think I've ever needed this so far, I wonder if it should be added to the core or can stay as a recipe/extension. --Petko
Thanks, this is a great solution. I fully support it being added to the core.
My use case is I have a number of pages with an ordering in the page names (e.g. 'Nameyyyy
'). I wish to only show a pagelist (say) in pages with names (say) greater than 'Name1957
'.
Oh, this is a rather simple comparison, could be done more efficiently with a name pattern. --Petko
(:pagelist name="Name19[5-9][7-9],Name[2-9][0-9][0-9][0-9]":) for 1957-9999 |
In fact we should implement name>=Name1957
. --Petko
I didn't know regex style patterns ([xyz])]) could be put in pagelist parameters.
I very much like the idea of implementing, where it makes sense, operators in addition to "=" in pagelists.
While my use case this time is for a name comparison, I can see the potential benefits of the more general use case for string comparison.