@@ -32,7 +32,10 @@ public class ExpressionEvaluator
3232 private static readonly string diactiticsKeywordsRegexPattern = "a-zA-Z_" + diactitics ;
3333
3434 private static readonly Regex varOrFunctionRegEx = new Regex ( $@ "^((?<sign>[+-])|(?<prefixOperator>[+][+]|--)|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[{ diactiticsKeywordsRegexPattern } ][{ diactiticsKeywordsRegexPattern } 0-9]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![{ diactiticsKeywordsRegexPattern } 0-9]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions . IgnoreCase | RegexOptions . Compiled ) ;
35- private static readonly Regex numberRegex = new Regex ( @"^(?<sign>[+-])?([0-9][0-9_]*[0-9]|\d)(?<hasdecimal>\.?([0-9][0-9_]*[0-9]|\d)(e[+-]?([0-9][0-9_]*[0-9]|\d))?)?(?<type>ul|[fdulm])?" , RegexOptions . IgnoreCase ) ;
35+
36+ private string numberRegexPattern = @"^(?<sign>[+-])?([0-9][0-9_]*[0-9]|\d)(?<hasdecimal>{0}?([0-9][0-9_]*[0-9]|\d)(e[+-]?([0-9][0-9_]*[0-9]|\d))?)?(?<type>ul|[fdulm])?" ;
37+ private Regex numberRegex = null ;
38+
3639 private static readonly Regex otherBasesNumberRegex = new Regex ( @"^(?<sign>[+-])?(?<value>0(?<type>x)([0-9a-f][0-9a-f_]*[0-9a-f]|[0-9a-f])|0(?<type>b)([01][01_]*[01]|[01]))" , RegexOptions . IgnoreCase ) ;
3740 private static readonly Regex stringBeginningRegex = new Regex ( "^(?<interpolated>[$])?(?<escaped>[@])?[\" ]" ) ;
3841 private static readonly Regex internalCharRegex = new Regex ( @"^['](\\[']|[^'])*[']" ) ;
@@ -163,14 +166,14 @@ private enum TryBlockEvaluatedState
163166 { "void" , typeof ( void ) }
164167 } ;
165168
166- private static Dictionary < string , Func < string , object > > numberSuffixToParse = new Dictionary < string , Func < string , object > > ( StringComparer . OrdinalIgnoreCase ) // Always Case insensitive, like in C#
169+ private static Dictionary < string , Func < string , CultureInfo , object > > numberSuffixToParse = new Dictionary < string , Func < string , CultureInfo , object > > ( StringComparer . OrdinalIgnoreCase ) // Always Case insensitive, like in C#
167170 {
168- { "f" , number => float . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) } ,
169- { "d" , number => double . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) } ,
170- { "u" , number => uint . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) } ,
171- { "l" , number => long . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) } ,
172- { "ul" , number => ulong . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) } ,
173- { "m" , number => decimal . Parse ( number , NumberStyles . Any , CultureInfo . InvariantCulture ) }
171+ { "f" , ( number , culture ) => float . Parse ( number , NumberStyles . Any , culture ) } ,
172+ { "d" , ( number , culture ) => double . Parse ( number , NumberStyles . Any , culture ) } ,
173+ { "u" , ( number , culture ) => uint . Parse ( number , NumberStyles . Any , culture ) } ,
174+ { "l" , ( number , culture ) => long . Parse ( number , NumberStyles . Any , culture ) } ,
175+ { "ul" , ( number , culture ) => ulong . Parse ( number , NumberStyles . Any , culture ) } ,
176+ { "m" , ( number , culture ) => decimal . Parse ( number , NumberStyles . Any , culture ) }
174177 } ;
175178
176179 private static Dictionary < char , string > stringEscapedCharDict = new Dictionary < char , string > ( )
@@ -529,6 +532,42 @@ private StringComparer StringComparerForCasing
529532 }
530533 }
531534
535+ private CultureInfo cultureInfoForNumberParsing = CultureInfo . InvariantCulture . Clone ( ) as CultureInfo ;
536+ private string optionNumberParsingDecimalSeparator = "." ;
537+
538+ /// <summary>
539+ /// Allow to change the decimal separator of numbers when parsing expressions.
540+ /// By default "."
541+ /// Warning if using comma change also OptionFunctionArgumentsSeparator and OptionInitializersSeparator otherwise it will create conflicts
542+ /// </summary>
543+ public string OptionNumberParsingDecimalSeparator
544+ {
545+
546+ get => optionNumberParsingDecimalSeparator ;
547+
548+ set
549+ {
550+ optionNumberParsingDecimalSeparator = value ;
551+ cultureInfoForNumberParsing . NumberFormat . NumberDecimalSeparator = value ;
552+
553+ numberRegex = new Regex ( string . Format ( numberRegexPattern , Regex . Escape ( optionNumberParsingDecimalSeparator ) ) , RegexOptions . IgnoreCase ) ;
554+ }
555+ }
556+
557+ /// <summary>
558+ /// Allow to change the separator of functions arguments.
559+ /// By default ","
560+ /// Warning must to be changed if OptionNumberParsingDecimalSeparator = "," otherwise it will create conflicts
561+ /// </summary>
562+ public string OptionFunctionArgumentsSeparator { get ; set ; } = "," ;
563+
564+ /// <summary>
565+ /// Allow to change the separator of Object and collections Initialization between { and } after the keyword new.
566+ /// By default ","
567+ /// Warning must to be changed if OptionNumberParsingDecimalSeparator = "," otherwise it will create conflicts
568+ /// </summary>
569+ public string OptionInitializersSeparator { get ; set ; } = "," ;
570+
532571 /// <summary>
533572 /// if <c>true</c> allow to add the prefix Fluid or Fluent before void methods names to return back the instance on which the method is call.
534573 /// if <c>false</c> unactive this functionality.
@@ -746,6 +785,7 @@ public ExpressionEvaluator()
746785 {
747786 Assemblies . AddRange ( AppDomain . CurrentDomain . GetAssemblies ( ) ) ;
748787 instanceCreationWithNewKeywordRegex = new Regex ( InstanceCreationWithNewKeywordRegexPattern ) ;
788+ numberRegex = new Regex ( string . Format ( numberRegexPattern , @"\." ) , RegexOptions . IgnoreCase ) ;
749789 castRegex = new Regex ( CastRegexPattern ) ;
750790 }
751791
@@ -1419,20 +1459,20 @@ private bool EvaluateNumber(string restOfExpression, Stack<object> stack, ref in
14191459 string type = numberMatch . Groups [ "type" ] . Value ;
14201460 string numberNoType = numberMatch . Value . Replace ( type , string . Empty ) . Replace ( "_" , "" ) ;
14211461
1422- if ( numberSuffixToParse . TryGetValue ( type , out Func < string , object > parseFunc ) )
1462+ if ( numberSuffixToParse . TryGetValue ( type , out Func < string , CultureInfo , object > parseFunc ) )
14231463 {
1424- stack . Push ( parseFunc ( numberNoType ) ) ;
1464+ stack . Push ( parseFunc ( numberNoType , cultureInfoForNumberParsing ) ) ;
14251465 }
14261466 }
14271467 else
14281468 {
14291469 if ( numberMatch . Groups [ "hasdecimal" ] . Success )
14301470 {
1431- stack . Push ( double . Parse ( numberMatch . Value . Replace ( "_" , "" ) , NumberStyles . Any , CultureInfo . InvariantCulture ) ) ;
1471+ stack . Push ( double . Parse ( numberMatch . Value . Replace ( "_" , "" ) , NumberStyles . Any , cultureInfoForNumberParsing ) ) ;
14321472 }
14331473 else
14341474 {
1435- stack . Push ( int . Parse ( numberMatch . Value . Replace ( "_" , "" ) , NumberStyles . Any , CultureInfo . InvariantCulture ) ) ;
1475+ stack . Push ( int . Parse ( numberMatch . Value . Replace ( "_" , "" ) , NumberStyles . Any , cultureInfoForNumberParsing ) ) ;
14361476 }
14371477 }
14381478
@@ -1478,7 +1518,7 @@ void Init(object element, List<string> initArgs)
14781518 {
14791519 int subIndex = subExpr . IndexOf ( "{" ) + 1 ;
14801520
1481- List < string > subArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( subExpr , ref subIndex , true , "," , "{" , "}" ) ;
1521+ List < string > subArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( subExpr , ref subIndex , true , OptionInitializersSeparator , "{" , "}" ) ;
14821522
14831523 if ( subArgs . Count == 2 )
14841524 {
@@ -1514,7 +1554,7 @@ void Init(object element, List<string> initArgs)
15141554
15151555 if ( instanceCreationMatch . Groups [ "isfunction" ] . Success )
15161556 {
1517- List < string > constructorArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true ) ;
1557+ List < string > constructorArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionFunctionArgumentsSeparator ) ;
15181558 i ++ ;
15191559
15201560 List < object > cArgs = constructorArgs . ConvertAll ( arg => Evaluate ( arg ) ) ;
@@ -1527,7 +1567,7 @@ void Init(object element, List<string> initArgs)
15271567 {
15281568 i += blockBeginningMatch . Length ;
15291569
1530- List < string > initArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , "," , "{" , "}" ) ;
1570+ List < string > initArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionInitializersSeparator , "{" , "}" ) ;
15311571
15321572 Init ( element , initArgs ) ;
15331573 }
@@ -1540,15 +1580,15 @@ void Init(object element, List<string> initArgs)
15401580 {
15411581 object element = Activator . CreateInstance ( type , new object [ 0 ] ) ;
15421582
1543- List < string > initArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , "," , "{" , "}" ) ;
1583+ List < string > initArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionInitializersSeparator , "{" , "}" ) ;
15441584
15451585 Init ( element , initArgs ) ;
15461586
15471587 stack . Push ( element ) ;
15481588 }
15491589 else if ( instanceCreationMatch . Groups [ "isArray" ] . Success )
15501590 {
1551- List < string > arrayArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , "," , "[" , "]" ) ;
1591+ List < string > arrayArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionInitializersSeparator , "[" , "]" ) ;
15521592 i ++ ;
15531593 Array array = null ;
15541594
@@ -1563,7 +1603,7 @@ void Init(object element, List<string> initArgs)
15631603 {
15641604 i += initInNewBeginningMatch . Length ;
15651605
1566- List < string > arrayElements = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , "," , "{" , "}" ) ;
1606+ List < string > arrayElements = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionInitializersSeparator , "{" , "}" ) ;
15671607 i ++ ;
15681608
15691609 if ( array == null )
@@ -1602,7 +1642,7 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
16021642
16031643 if ( varFuncMatch . Groups [ "isfunction" ] . Success )
16041644 {
1605- List < string > funcArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true ) ;
1645+ List < string > funcArgs = GetExpressionsBetweenParenthesesOrOtherImbricableBrackets ( expr , ref i , true , OptionFunctionArgumentsSeparator ) ;
16061646 if ( varFuncMatch . Groups [ "inObject" ] . Success )
16071647 {
16081648 if ( stack . Count == 0 || stack . Peek ( ) is ExpressionOperator )
0 commit comments