Jump to content

Help:Switch parser function

From Wikipedia, the free encyclopedia

The switch parser function, coded as #switch, selects the first matching branch in a list of choices, acting as a case statement.

Each branch can be a value, an expression (calculation), or a template call,[1] evaluated and compared to match the value of the switch. Although many #switch structures are used to branch among a simple set of values, the branches can also include boolean expressions to act as a set of pre-conditions to be tested until one tests true, acting as an if-elseif-elseif-elseif-else structure.

Because it is a parser function, a #switch can be used inside any page, even in article text. Still, in most cases, a #switch is typically used inside a template, to branch depending on a parameter value passed to the template.

General format

[edit]

The #switch function can be a one-line form:

{{#switch: {{{x}}} |1=one |2=two |3|4|5=range 3–5 |other}}

That one-line #switch would read the value of {{{x}}}. For a value of 1 it would return "one". For a value of 2 it would return "two". For the values 3, 4 or 5 it would return "range 3–5". For any other value, or a null value, it would return "other".

It is customary to format the #switch function into multiple lines, especially with higher-complexity code:

{{#switch: {{{x}}}
 | 1 = one
 | 2 = two
 | #default = other
 | 3|4|5 = range 3–5
 | {{#expr: 2*3}} = six
 | {{#expr: 2*3+1}} = {{lc:SEVEN}} <!-- Use the lc: parser function to convert to lowercase -->
}}

This is the same as above, but with these changes:

  • Split into multiple lines. The 3|4|5 part can also be further broken down into one per line: use this for longer match-terms.
  • The default case is put in a different position using the magical match-entry #default, which allows it to be put first, last, or anywhere in-between. This is functionally the same as putting it in the end, only a stylistic preference: the default case still needs to be evaluated last.
    • This is also the same as specifying a line | = other. #switch does not allow you to specifically match the empty string. However, we can use the difference between {{{x}}} and {{{x|}}} to detect whether the parameter x is truly empty or set to contain the string "{{{x}}}":
      | = {{#ifeq:{{{x|}}}|{{{x}}}|other|empty}}
      
    • If no default is specified and no case matches the supplied value, a null value is returned.
  • We use two {{#expr:}} invocations to generate the numbers 6 and 7. This is unnecessary in our case, but it serves to show a point: "moving parts" like templates, modules, and parser functions can be used not only on the value being matched ({{{x}}}), but on the expression used to match the value (what's on the left side of the equal-sign).
  • We also show off the use of a parser function in the output of a case. Again, "moving parts" can be freely used there.

Using switches as if-elseif-else

[edit]

A #switch function can be structured as a set of pre-conditions which are tested until one is true (equal to "1"). For example to pre-screen numbers to avoid division by zero, in formula: x/x2 + y/y2

{{#switch: 1
| {{#ifeq:{{{x2|none}}}|none|1|0}} = Parameter x2 has no data.
| {{#ifeq:{{{y2|none}}}|none|1|0}} = Parameter y2 has no data.
| {{#expr: {{{x2}}} = 0}} = Parameter x2 is 0 – cannot divide.
| {{#expr: {{{y2}}} = 0}} = Parameter y2 is 0 – cannot divide.
| 1 = {{#expr: {{{x}}}/{{{x2}}} + {{{y}}}/{{{y2}}}}}
}}

When testing x2 and y2, if either of them is empty or zero, then the #switch ends with a warning message, rather than calculating the weighted average of the two amounts x, y, with x2 and y2. Each branch acts as a pre-condition, so the whole #switch structure performs as equivalent to if-elseif-elseif-elseif-else, even though an #if-function structure cannot have an "elseif" clause. Note the 2 types of data compared:

Alphabetic data
An alpha character string can be compared in the #switch by using #ifeq: as follows:     {{#ifeq:{{{x2|none}}}|none|1|0}},
where the result would be "1" when true, or "0" when false.
Numeric data
Some numbers can be compared in the #switch by using #expr as follows:     {{#expr: {{{y2}}} = 0}} or {{#expr: {{{x}}} < 41500}},
where each result would be "1" when true, or "0" when false.

Another example, to test an amount "n" to determine the number of decimal digits:

{{#switch: 1
| {{#expr: floor({{{n}}}*100) <> {{{n}}}*100}} = 3
| {{#expr: floor({{{n}}}*10) <> {{{n}}}*10}} = 2
| {{#expr: floor( {{{n}}} ) <> {{{n}}} }} = 1
| {{#expr: {{{n}}} mod 1000 = 0}} = −3
| {{#expr: {{{n}}} mod 100 = 0 }} = −2
| {{#expr: {{{n}}} mod 10 = 0 }} = −1
| 1 = 0
}}

Here we use #switch: 1 to stack a set of pre-conditions which are tested, in sequence, until one is true (equal to "1").

Tests do not have to start with #switch: 1. In particular, #switch: yes is very useful when using {{str startswith}} and {{str endswith}} as they return "yes" on true and empty on false. The same behavior is seen in {{yesno}}.

Performance considerations

[edit]

Templates using such convoluted switch statements as to suffer significant performance issues should be translated to Lua, if that will make them simpler or significantly faster. The below discussion should rarely be relevant but is preserved for reference.

It is allowed to put over over 1,000–2,000 branches in a #switch. However, they are processed linearly from top to down. This means that the upper branches are executed sooner and the bottom branches must wait for comparisons of all higher branches. Hence, the top branch should be the most-used case, unless pre-screening of data is done in the early branches.

It can also be advantageous to switch to nested #switch structures with each level having fewer than 100 branches. If the values to be matched are strings, a logic similar to a trie can be used. There are two approaches:

<!-- Assuming we start with... -->
{{#switch: {{{value|}}}
|bee=This is a kind of bug.
|egg=That is a big cell.
|example=That is something we use to explain things.
|eggample=That is what a chicken uses to explain things
|gee=This is some kind of singer.
}}

<!-- Use {{padleft:|1|{{{value|}}}}} to extract the first letter (change the "1" to match several letters). -->
{{#switch: {{padleft:|1|{{{value|}}}}}
|e={{#switch: {{{value}}}
   |egg=That is a big cell.
   |example=That is something we use to explain things.
   |eggample=That is what a chicken uses to explain things.
   }}
<!-- Everything else remains on the #default branch. -->
|#default={{#switch: {{{value|}}}
  |bee=This is a kind of bug.
  |gee=This is some kind of singer.
  }}
}}

<!-- Or the if-elseif-else technique from above. -->
{{#switch: yes
|{{str startswith|{{{value|}}}|e}} =
   {{#switch: {{{value}}}
   |egg=That is a big cell.
   |example=That is something we use to explain things.
   |eggample=That is what a chicken uses to explain things.
   }}
|#default=
  {{#switch: {{{value|}}}
  |bee=This is a kind of bug.
  |gee=This is some kind of singer.
  }}
}}

Another common split might be to separate numeric values into frequent ranges, followed by all others.

Notes

[edit]
  1. ^ A template call (also known as template tag) has two "braces" on either side of the template page name and does not require the "Template:" prefix. For example, the following are equivalent template calls: {{Template:Foobar}} and {{Foobar}}.

See also

[edit]