Comma Enabled Markup Expressions

Summary: Markup Expressions which allow input of string values which use a comma as decimal separator.
Version: 2026-02
Prerequisites:
Status:
Maintainer: HansB
License: (Apache 2.0|BSD-3-clause|BSD-2-clause|GPL|LGPL|MIT|MPL-2.0|CDDL-1.0|EPL-1.0) - OpenSourceLicenses Cookbook:Cookbook Licenses
Users: (view / edit)

Description

Markup Expressions which allow input of string values which use a comma as decimal separator.

Installation

To enable any of the Markup Expressions shown here add the code into your config.php file. Any php recipe script listed here copy to your cookbook folder and include in the normal way in your config.php file.
A co suffix as part of a ME name indicates that it is specific for use with numbers in decimal comma format.

{(add)} {(mul)} {(div)}) {(sub)}

The four basic arithmetic operations (+ * - /)) for two or more numbers with decimal commas or decimal dots (but don't mix the decimal formats!). These expressions could replace the arithmetic expressions from MarkupExprPlus. For this make sure to include before that recipe. All MXs can have PTVs as argument inputs, or other MXs which output a single number, as integer or float value.

// basic arithmetic operations addition, subtraction, multiplication, division
// (add num1 num2 ...) (sub ...) (mul ...) (div ...) 
$MarkupExpr['add'] = 'Mx_ArithX("+", $args)';
$MarkupExpr['sub'] = 'Mx_ArithX("-", $args)';
$MarkupExpr['mul'] = 'Mx_ArithX("*", $args)';
$MarkupExpr['div'] = 'Mx_ArithX("/", $args)';
function Mx_ArithX($op, $args) {
  $CF = 0;
  $ar = array();
  foreach ($args as $i => $v) {
    if (strstr($v,",")) { //comma in value; assume decimal comma format
         $CF = 1; //decimal comma flag
         $ar[$i] = floatval(str_replace(",",'.',str_replace(".",'',$v)));
    } else  $ar[$i] = floatval($v);
  }
  $x = array_shift($ar);
  foreach($ar as $i => $v) {
    if ($op=='+') $x = $x + $v;
    if ($op=='*') $x = $x * $v;
    if ($op=='-') $x = $x - $v;
    if ($op=='/') { if ($v==0) $v=1; //neutralise division by zero
        $x = $x / $v;
    }
  }
  if ($CF== 1) $x = str_replace(".",',',$x); //reset decimal comma if needed
  return $x;
}

{(unfmt)}

Converts a number(string) with decimal comma and [optional] dots as thousands separator to floatval number type. Useful when needing to use one of the 'numfmt' MEs, which use PHP number_format() function.

// (unfmt  <comma-fmt-number>)
$MarkupExpr['unfmt'] = 'ME_Strip_Comma_Fmt($args[0])';
function ME_Strip_Comma_Fmt($a) {
   return floatval(str_replace(",",".",str_replace(".","",$a)));
}

{(math)}

Based on the 'calc' ME on page Markup Expression Samples, renamed to 'math' because it can handle higher math functions as well.
Uses basic and extended math functions. Use + - * / ^ as operators, other PHP math functions with brackets and comma separated arguments: pow(), sqrt(), sin(), cos(), tan(), asin(), acos(), atan(), log(), max(), min(), abs(), ceil(), floor(), round(), rand(), fmod(), deg2rad(), rad2deg(); constant: pi.Example: {(calc 'sqrt(7^2 + 9^2)')}

If this ME is given wrong input, anything which is not a mathematical expression, it will fail and crash your page. If the input comes from some input form this can easily happen. The ME uses the PHP eval() function, which will not give error notice, but just crashes the page on bad input!

]
// (math '<math expression>') expression in quotes
// values, operatores, () brackets must have spaces between
$MarkupExpr['math'] = 'MxMathCalc($args)';
function MxMathCalc($args) {
	global $MxCalcChars, $MxCalcFunc1, $MxCalcFunc2;
	//allowed characters (operators, digits, brackets etc) apart from function names below
	SDV($MxCalcChars, "/^[-+*,\\/% ><=()0-9.^]+$/");
	//math functions with single argument
	SDV($MxCalcFunc1, array(
		'sqrt','sin','cos','tan','asin','acos','atan','log',
		'abs','ceil','floor','round','deg2rad','rad2deg',
	));	
	//math functions with 2 or more arguments, constants, and others
	SDV($MxCalcFunc2, array(
		'pow','max','min','rand','fmod','pi',
	));
	$mathfn = array_merge($MxCalcFunc1, $MxCalcFunc2); 
	$arg = implode(" ", $args);
	//nothing to do
	if ($arg == '') return "empty input!";
	//check for comma as decimal point,  replace , with .
    $CD = 0;
    if (strstr($arg,",")) {
        $arg = str_replace(",",".",$arg);
        $CD = 1;
    }   
    $str = $arg; 
    //check if math expression has only allowed characters and function names
	foreach($mathfn as $fn) {
		$str = str_replace($fn, '', $str);
	}
	if ($str!='' && !preg_match($MxCalcChars, $str, $m)) return "Input error!";
	//translate easy input
	$arg = str_replace('pi', M_PI, $arg);
	$arg = preg_replace("/(\\-?[\\d.]+)\\^(\\-?[\\d.]+)/", "pow($1, $2)", $arg);
	foreach($MxCalcFunc1 as $fn)
		$arg = preg_replace("/{$fn}\\s?(\\-?[\\d.]+)/", "{$fn}($1)", $arg);
	//do the work
	eval("\$res = $arg;");
	//provide for 0 as result from comparison operations
	if ($res=='')
		if (preg_match("/[><=]/", $arg))	$res = '0';
    if ($CD==1)
        $res = str_replace(".",",",$res); //restore comma as decimal point
	return $res;
}

{(calc)}

This is based on the 'math' ME on Markup Expression Samples. The expression can be put into quotes, which then allows use of round brackets and dense writing (avoiding space gaps). Without quotes it can be used by putting spaces between all values and operators, and if brackets are needed, using square brackets [ ... ] . Renamed because it is more limited than the 'math' ME below. I rewrote this, as the original threw up errors.

If this ME is given wrong input, anything which is not a mathematical expression, it will fail and crash your page. If the input comes from some input form thius can easily happen. The ME uses the PHP eval() function, which will not give error notice, but just crashes the page on bad input!

]
// (calc 'a+b*(c-d)') expression as string in quotes
// (calc a + b * [ c - d ] ) expression with spaces and optional square [ ]
$MarkupExpr['calc'] = 'Mx_CalcX($args)';
function Mx_CalcX($args) {
    $xpr = implode(' ', $args);
    $CF = (strstr($xpr,","))? 1 : 0; //set flag for comma decimal separator
    $a = array( '[', ']', '&lt;','&gt;', ',');
    $b = array( '(', ')',  '<',   '>'  , '.');
    $xpr = str_replace($a, $b, $xpr);
    $defuse = array(
        '/[A-Za-z]\w*/'           =>  '0', 
        '/[^0-9.+-\/*%!()<>=]/'   =>  '',
        '/(^|[^0-9.])0+([1-9.])/' =>  '$1$2' ,
        '/(?<![!<>=])=/'          =>  '==',
    );
    foreach ($defuse as $pat => $rep)                       
        $xpr = preg_replace($pat ,$rep , $xpr);
    $res = eval("return ($xpr);");
    if ($CF==1) $res = str_replace(".",",",$res); //reset comma sep.
    return $res;    
}

{(euroco)}

For output a number with Euro symbol added, decimal comma, dot as thousands separator, 2 digits.

// (euroco num) formats number to 2 digits, decimal comma, dot thousands separator,
// Euro symbol at front. Use as final wrapper ME for finanancial output.
$MarkupExpr['euroco'] = 'ME_Euro_Comma($args[0])';
function ME_Euro_Comma($val) {
    $str = number_format(floatval($val),2,",",".");
    return "&euro;&nbsp;".$str;
}

Configuration

Internationalization

The following strings can be translated in an XLPage:

Usage

Notes

To do / some day / maybe

If you have future plans or wishes for this recipe.

Change log / Release notes

If the recipe has multiple releases, then release notes can be placed here. Note that it's often easier for people to work with "release dates" instead of "version numbers".

See also

Contributors

Comments

See discussion at CommaEnabledMarkupExpressions-Talk

User notes : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.