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.

{(mulco)}

For multiplying two or more numbers, which have comma as decimal separator

// (mulco  num1 num2 ... ...) 
// multiplies two or more values in comma as decimal separator format 
// returns number in same format with tow decimal places
$MarkupExpr['mulco'] = 'ME_Comma_Multi($argp)';
function ME_Comma_Multi($p) {
  $a = array();
  foreach ($p[''] as $i => $v)
      $a[$i] = floatval(str_replace(",",'.',str_replace(".",'',$v)));
  $x = 1;
  foreach($a as $i => $v)
      $x = $x * $v;
  $x = number_format($x,2,",","."); //2 decimal places. up to poss 10 could be shown
  return $x;
}

{(sumco)}

For adding two or more numbers, which have comma as decimal separator

// (sumco num1 num2 ... ...)
// sums (adds together) two or more values in comma as decimal separator format 
// returns number in same format with tow decimal places
$MarkupExpr['sumco'] = 'ME_Comma_Sum($argp)';
function ME_Comma_Sum($p) {
    $a = array();
    foreach ($p[''] as $i => $v)
        $a[$i] = floatval(str_replace(",",'.',str_replace(".",'',$v)));
    $x = 0;
    foreach($a as $i => $v)
        $x = $x + $v;
    $x = number_format($x,2,",","."); //2 decimal places. up to poss 10 could be shown
    // $x = str_replace(".",",", $x); //alternative; reformat with comma, variable decimal digits
    return $x;
}

{(unfmt)}

Converts a number in comma format (comma as decimal separator, dots{optional] 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)')}

]
// (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, but the expression needs to be put into quotes, which then allows use of round brackets and dense writing (avoiding space gaps). Renamed because it is more limited than the 'math' ME below. I rewrote this, as the original threw up errors.

]
// (calc "a+b*(c-d)") expression as string in quotes
$MarkupExpr['calc'] = 'ME_mathX($args[0])';
function ME_mathX($xpr) {
    $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;    
}

{(calcu)}

This ME is similar to 'calc', but arguments are not enclosed in quotes, and if brackets are needed they must be square, never round. Also all arguments including operators and brackets must be separated by spaces. Supports basic math functions. Supports comma as decimal sep.

// (math a + b * [ c - d ] ) expression with spaces and optional square [ ]
$MarkupExpr['calcu'] = 'ME_math($argp)';
function ME_math($argp) {
    $xpr = implode(' ', $argp['']);
    $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;    
}

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.