Skip to content

Commit 5007c3f

Browse files
committed
Compiled regex didnt improve perfs ???
1 parent e132fd0 commit 5007c3f

File tree

3 files changed

+111
-71
lines changed

3 files changed

+111
-71
lines changed

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 71 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,37 @@ public class ExpressionEvaluator
1616
{
1717
#region Regex declarations
1818

19-
private static Regex varOrFunctionRegEx = new Regex(@"^((?<sign>[+-])|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![a-zA-Z0-9_]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
20-
private static Regex numberRegex = new Regex(@"^(?<sign>[+-])?\d+(?<hasdecimal>\.?\d+(e[+-]?\d+)?)?(?<type>ul|[fdulm])?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
21-
private static Regex stringBeginningRegex = new Regex("^(?<interpolated>[$])?(?<escaped>[@])?[\"]", RegexOptions.Compiled);
22-
private static Regex internalCharRegex = new Regex(@"^['](\\[']|[^'])*[']", RegexOptions.Compiled);
19+
private static Regex varOrFunctionRegEx = new Regex(@"^((?<sign>[+-])|(?<inObject>(?<nullConditional>[?])?\.)?)(?<name>[a-zA-Z_][a-zA-Z0-9_]*)\s*((?<assignationOperator>(?<assignmentPrefix>[+\-*/%&|^]|<<|>>)?=(?![=>]))|(?<postfixOperator>([+][+]|--)(?![a-zA-Z0-9_]))|((?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?))", RegexOptions.IgnoreCase);
20+
private static Regex numberRegex = new Regex(@"^(?<sign>[+-])?\d+(?<hasdecimal>\.?\d+(e[+-]?\d+)?)?(?<type>ul|[fdulm])?", RegexOptions.IgnoreCase);
21+
private static Regex stringBeginningRegex = new Regex("^(?<interpolated>[$])?(?<escaped>[@])?[\"]");
22+
private static Regex internalCharRegex = new Regex(@"^['](\\[']|[^'])*[']");
2323
private static Regex castRegex = new Regex(@"^\(\s*(?<typeName>[a-zA-Z_][a-zA-Z0-9_\.\[\]<>]*[?]?)\s*\)");
24-
private static Regex indexingBeginningRegex = new Regex(@"^[?]?\[", RegexOptions.Compiled);
25-
private static Regex endOfStringWithDollar = new Regex("^[^\"{]*[\"{]", RegexOptions.Compiled);
26-
private static Regex endOfStringWithoutDollar = new Regex("^[^\"]*[\"]", RegexOptions.Compiled);
27-
private static Regex endOfStringInterpolationRegex = new Regex("^[^}\"]*[}\"]", RegexOptions.Compiled);
28-
private static Regex stringBeginningForEndBlockRegex = new Regex("[$]?[@]?[\"]$", RegexOptions.Compiled);
29-
private static Regex lambdaExpressionRegex = new Regex(@"^\s*(?<args>(\s*[(]\s*([a-zA-Z_][a-zA-Z0-9_]*\s*([,]\s*[a-zA-Z_][a-zA-Z0-9_]*\s*)*)?[)])|[a-zA-Z_][a-zA-Z0-9_]*)\s*=>(?<expression>.*)$", RegexOptions.Singleline | RegexOptions.Compiled);
30-
private static Regex lambdaArgRegex = new Regex(@"[a-zA-Z_][a-zA-Z0-9_]*", RegexOptions.Compiled);
24+
private static Regex indexingBeginningRegex = new Regex(@"^[?]?\[");
25+
private static Regex endOfStringWithDollar = new Regex("^[^\"{]*[\"{]");
26+
private static Regex endOfStringWithoutDollar = new Regex("^[^\"]*[\"]");
27+
private static Regex endOfStringInterpolationRegex = new Regex("^[^}\"]*[}\"]");
28+
private static Regex stringBeginningForEndBlockRegex = new Regex("[$]?[@]?[\"]$");
29+
private static Regex lambdaExpressionRegex = new Regex(@"^\s*(?<args>(\s*[(]\s*([a-zA-Z_][a-zA-Z0-9_]*\s*([,]\s*[a-zA-Z_][a-zA-Z0-9_]*\s*)*)?[)])|[a-zA-Z_][a-zA-Z0-9_]*)\s*=>(?<expression>.*)$", RegexOptions.Singleline);
30+
private static Regex lambdaArgRegex = new Regex(@"[a-zA-Z_][a-zA-Z0-9_]*");
3131

3232
private static readonly string instanceCreationWithNewKeywordRegexPattern = @"^new\s+(?<name>[a-zA-Z_][a-zA-Z0-9_.]*)\s*(?<isgeneric>[<](?>[^<>]+|(?<gentag>[<])|(?<-gentag>[>]))*(?(gentag)(?!))[>])?(?<isfunction>[(])?";
33-
private Regex instanceCreationWithNewKeywordRegex = new Regex(instanceCreationWithNewKeywordRegexPattern, RegexOptions.Compiled);
33+
private Regex instanceCreationWithNewKeywordRegex = new Regex(instanceCreationWithNewKeywordRegexPattern);
3434
private static readonly string primaryTypesRegexPattern = @"(?<=^|[^a-zA-Z_])(?<primaryType>object|string|bool[?]?|byte[?]?|char[?]?|decimal[?]?|double[?]?|short[?]?|int[?]?|long[?]?|sbyte[?]?|float[?]?|ushort[?]?|uint[?]?|void)(?=[^a-zA-Z_]|$)";
35-
private Regex primaryTypesRegex = new Regex(primaryTypesRegexPattern, RegexOptions.Compiled);
35+
private Regex primaryTypesRegex = new Regex(primaryTypesRegexPattern);
3636

3737
// To remove comments in scripts based on https://stackoverflow.com/questions/3524317/regex-to-strip-line-comments-from-c-sharp/3524689#3524689
3838
private static readonly string blockComments = @"/\*(.*?)\*/";
3939
private static readonly string lineComments = @"//[^\r\n]*";
4040
private static readonly string stringsIgnore = @"""((\\[^\n]|[^""\n])*)""";
4141
private static readonly string verbatimStringsIgnore = @"@(""[^""]*"")+";
42-
private static readonly Regex removeCommentsRegex = new Regex($"{blockComments}|{lineComments}|{stringsIgnore}|{verbatimStringsIgnore}", RegexOptions.Singleline | RegexOptions.Compiled);
43-
private static readonly Regex newLineCharsRegex = new Regex(@"\r\n|\r|\n", RegexOptions.Compiled);
42+
private static readonly Regex removeCommentsRegex = new Regex($"{blockComments}|{lineComments}|{stringsIgnore}|{verbatimStringsIgnore}", RegexOptions.Singleline);
43+
private static readonly Regex newLineCharsRegex = new Regex(@"\r\n|\r|\n");
4444

4545
// For script only
46-
private static readonly Regex blockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>while|for|if|else\s+if)\s*[(]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
47-
private static readonly Regex elseblockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>else)(?![a-zA-Z0-9_])", RegexOptions.IgnoreCase| RegexOptions.Compiled);
48-
private static readonly Regex blockBeginningRegex = new Regex(@"^\s*[{]", RegexOptions.Compiled);
49-
private static readonly Regex returnKeywordRegex = new Regex(@"^return(\s+|\()", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
46+
private static readonly Regex blockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>while|for|if|else\s+if)\s*[(]", RegexOptions.IgnoreCase);
47+
private static readonly Regex elseblockKeywordsBeginningRegex = new Regex(@"^\s*(?<keyword>else)(?![a-zA-Z0-9_])", RegexOptions.IgnoreCase);
48+
private static readonly Regex blockBeginningRegex = new Regex(@"^\s*[{]");
49+
private static readonly Regex returnKeywordRegex = new Regex(@"^return(\s+|\()", RegexOptions.IgnoreCase | RegexOptions.Singleline);
5050

5151
#endregion
5252

@@ -424,8 +424,8 @@ public bool OptionCaseSensitiveEvaluationActive
424424
simpleDoubleMathFuncsDictionary = new Dictionary<string, Func<double, double>>(simpleDoubleMathFuncsDictionary, StringComparerForCasing);
425425
doubleDoubleMathFuncsDictionary = new Dictionary<string, Func<double, double, double>>(doubleDoubleMathFuncsDictionary, StringComparerForCasing);
426426
complexStandardFuncsDictionary = new Dictionary<string, Func<ExpressionEvaluator, List<string>, object>>(complexStandardFuncsDictionary, StringComparerForCasing);
427-
instanceCreationWithNewKeywordRegex = new Regex(instanceCreationWithNewKeywordRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase) | RegexOptions.Compiled);
428-
primaryTypesRegex = new Regex(primaryTypesRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase) | RegexOptions.Compiled);
427+
instanceCreationWithNewKeywordRegex = new Regex(instanceCreationWithNewKeywordRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
428+
primaryTypesRegex = new Regex(primaryTypesRegexPattern, (optionCaseSensitiveEvaluationActive ? RegexOptions.None : RegexOptions.IgnoreCase));
429429
}
430430
}
431431

@@ -2091,8 +2091,9 @@ private List<string> GetExpressionsBetweenParenthis(string expr, ref int i, bool
20912091
int bracketCount = 1;
20922092
for (; i < expr.Length; i++)
20932093
{
2094-
Match internalStringMatch = stringBeginningRegex.Match(expr.Substring(i));
2095-
Match internalCharMatch = internalCharRegex.Match(expr.Substring(i));
2094+
string subExpr = expr.Substring(i);
2095+
Match internalStringMatch = stringBeginningRegex.Match(subExpr);
2096+
Match internalCharMatch = internalCharRegex.Match(subExpr);
20962097

20972098
if (internalStringMatch.Success)
20982099
{
@@ -2233,76 +2234,82 @@ private static object ChangeType(object value, Type conversionType)
22332234
return Convert.ChangeType(value, conversionType);
22342235
}
22352236

2236-
//private string GetCodeUntilEndOfString(string subExpr, Match stringBeginningMatch)
2237-
//{
2238-
// Match codeUntilEndOfStringMatch = stringBeginningMatch.Value.Contains("$") ? endOfStringWithDollar.Match(subExpr) : endOfStringWithoutDollar.Match(subExpr);
2239-
// string result = subExpr;
2237+
private string GetCodeUntilEndOfString(string subExpr, Match stringBeginningMatch)
2238+
{
2239+
StringBuilder stringBuilder = new StringBuilder();
22402240

2241-
// if (codeUntilEndOfStringMatch.Success)
2242-
// {
2243-
// if (codeUntilEndOfStringMatch.Value.EndsWith("\""))
2244-
// {
2245-
// result = codeUntilEndOfStringMatch.Value;
2246-
// }
2247-
// else if (codeUntilEndOfStringMatch.Value.EndsWith("{") && codeUntilEndOfStringMatch.Length < subExpr.Length)
2248-
// {
2249-
// if (subExpr[codeUntilEndOfStringMatch.Length] == '{')
2250-
// {
2251-
// result = codeUntilEndOfStringMatch.Value + "{"
2252-
// + GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + 1), stringBeginningMatch);
2253-
// }
2254-
// else
2255-
// {
2256-
// string interpolation = GetCodeUntilEndOfStringInterpolation(subExpr.Substring(codeUntilEndOfStringMatch.Length));
2257-
// result = codeUntilEndOfStringMatch.Value + interpolation
2258-
// + GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + interpolation.Length), stringBeginningMatch);
2259-
// }
2260-
// }
2261-
// }
2241+
GetCodeUntilEndOfString(subExpr, stringBeginningMatch, ref stringBuilder);
22622242

2263-
// return result;
2264-
//}
2243+
return stringBuilder.ToString();
2244+
}
22652245

2266-
private string GetCodeUntilEndOfString(string subExpr, Match stringBeginningMatch)
2246+
private void GetCodeUntilEndOfString(string subExpr, Match stringBeginningMatch, ref StringBuilder stringBuilder)
22672247
{
22682248
Match codeUntilEndOfStringMatch = stringBeginningMatch.Value.Contains("$") ? endOfStringWithDollar.Match(subExpr) : endOfStringWithoutDollar.Match(subExpr);
2269-
StringBuilder result = new StringBuilder();
22702249

22712250
if (codeUntilEndOfStringMatch.Success)
22722251
{
22732252
if (codeUntilEndOfStringMatch.Value.EndsWith("\""))
22742253
{
2275-
result.Append(codeUntilEndOfStringMatch.Value);
2254+
stringBuilder.Append(codeUntilEndOfStringMatch.Value);
22762255
}
22772256
else if (codeUntilEndOfStringMatch.Value.EndsWith("{") && codeUntilEndOfStringMatch.Length < subExpr.Length)
22782257
{
22792258
if (subExpr[codeUntilEndOfStringMatch.Length] == '{')
22802259
{
2281-
result.Append(codeUntilEndOfStringMatch.Value);
2282-
result.Append("{");
2283-
result.Append(GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + 1), stringBeginningMatch));
2260+
stringBuilder.Append(codeUntilEndOfStringMatch.Value);
2261+
stringBuilder.Append("{");
2262+
GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + 1), stringBeginningMatch, ref stringBuilder);
22842263
}
22852264
else
22862265
{
22872266
string interpolation = GetCodeUntilEndOfStringInterpolation(subExpr.Substring(codeUntilEndOfStringMatch.Length));
2288-
result.Append(codeUntilEndOfStringMatch.Value);
2289-
result.Append(interpolation);
2290-
result.Append(GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + interpolation.Length), stringBeginningMatch));
2267+
stringBuilder.Append(codeUntilEndOfStringMatch.Value);
2268+
stringBuilder.Append(interpolation);
2269+
GetCodeUntilEndOfString(subExpr.Substring(codeUntilEndOfStringMatch.Length + interpolation.Length), stringBeginningMatch, ref stringBuilder);
22912270
}
22922271
}
22932272
else
22942273
{
2295-
result.Append(subExpr);
2274+
stringBuilder.Append(subExpr);
22962275
}
22972276
}
22982277
else
22992278
{
2300-
result.Append(subExpr);
2279+
stringBuilder.Append(subExpr);
23012280
}
2302-
2303-
return result.ToString();
23042281
}
23052282

2283+
//private string GetCodeUntilEndOfStringInterpolation(string subExpr)
2284+
//{
2285+
// Match endOfStringInterpolationMatch = endOfStringInterpolationRegex.Match(subExpr);
2286+
// StringBuilder result = new StringBuilder();
2287+
2288+
// if (endOfStringInterpolationMatch.Success)
2289+
// {
2290+
// if (endOfStringInterpolationMatch.Value.EndsWith("}"))
2291+
// {
2292+
// result.Append(endOfStringInterpolationMatch.Value);
2293+
// }
2294+
// else
2295+
// {
2296+
// Match stringBeginningForEndBlockMatch = stringBeginningForEndBlockRegex.Match(endOfStringInterpolationMatch.Value);
2297+
2298+
// string subString = GetCodeUntilEndOfString(subExpr.Substring(endOfStringInterpolationMatch.Length), stringBeginningForEndBlockMatch);
2299+
2300+
// result.Append(endOfStringInterpolationMatch.Value);
2301+
// result.Append(subString);
2302+
// result.Append(GetCodeUntilEndOfStringInterpolation(subExpr.Substring(endOfStringInterpolationMatch.Length + subString.Length)));
2303+
// }
2304+
// }
2305+
// else
2306+
// {
2307+
// result.Append(subExpr);
2308+
// }
2309+
2310+
// return result.ToString();
2311+
//}
2312+
23062313
private string GetCodeUntilEndOfStringInterpolation(string subExpr)
23072314
{
23082315
Match endOfStringInterpolationMatch = endOfStringInterpolationRegex.Match(subExpr);
@@ -2328,6 +2335,7 @@ private string GetCodeUntilEndOfStringInterpolation(string subExpr)
23282335
return result;
23292336
}
23302337

2338+
23312339
#endregion
23322340

23332341
#region Utils private sub classes for parsing and interpretation

TryWindow/MainWindow.xaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
mc:Ignorable="d"
1010
Title="Expression Evaluate" Width="400" Height="300">
1111
<DockPanel>
12+
1213
<StackPanel DockPanel.Dock="Bottom">
14+
<DockPanel>
15+
<Label DockPanel.Dock="Left"
16+
Content="Iterations"
17+
Padding="2,0"/>
18+
<TextBox x:Name="IterationsTextBox"
19+
Text="1" />
20+
</DockPanel>
1321
<Button x:Name="CalculateButton" Content="_Execute" IsDefault="True" Click="CalculateButton_Click" />
1422
<Button x:Name="CancelButton"
1523
Content="_Cancel"

TryWindow/MainWindow.xaml.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,19 @@ namespace TryWindow
1515
/// </summary>
1616
public partial class MainWindow : Window
1717
{
18-
private string persistFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "code.cs");
18+
private string persistCodeFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "code.cs");
19+
private string persistIterationFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "iterations");
1920

2021
private CancellationTokenSource cancellationTokenSource = null;
2122

2223
public MainWindow()
2324
{
2425
InitializeComponent();
2526

26-
if (File.Exists(persistFileName))
27-
ScriptTextBox.Text = File.ReadAllText(persistFileName);
27+
if (File.Exists(persistCodeFileName))
28+
ScriptTextBox.Text = File.ReadAllText(persistCodeFileName);
29+
if (File.Exists(persistIterationFileName))
30+
IterationsTextBox.Text = File.ReadAllText(persistIterationFileName);
2831
}
2932

3033
private async void CalculateButton_Click(object sender, RoutedEventArgs e)
@@ -44,17 +47,28 @@ private async void CalculateButton_Click(object sender, RoutedEventArgs e)
4447
try
4548
{
4649
string script = evaluator.RemoveComments(ScriptTextBox.Text);
50+
string sIteration = IterationsTextBox.Text;
4751
Exception exception = null;
4852
cancellationTokenSource = new CancellationTokenSource();
4953
cancellationTokenSource.Token.ThrowIfCancellationRequested();
5054
string result = await Task.Run<string>(() =>
5155
{
56+
if (!int.TryParse(sIteration, out int iterations))
57+
iterations = 1;
58+
59+
iterations = Math.Max(0, iterations);
60+
5261
stopWatch.Start();
5362
try
5463
{
5564
using (cancellationTokenSource.Token.Register(Thread.CurrentThread.Abort))
5665
{
57-
return evaluator.ScriptEvaluate(script)?.ToString() ?? "null or void";
66+
string innerResult = "null or void";
67+
68+
for(int i = 0; i < iterations; i++)
69+
innerResult = evaluator.ScriptEvaluate(script)?.ToString() ?? "null or void";
70+
71+
return innerResult;
5872
}
5973
}
6074
catch(Exception innerException)
@@ -102,19 +116,29 @@ private void CancelButton_Click(object sender, RoutedEventArgs e)
102116

103117
private void ScriptTextBox_TextChanged(object sender, EventArgs e)
104118
{
105-
Save();
119+
SaveCode();
106120
}
107121

108122
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
109123
{
110-
Save();
124+
SaveCode();
125+
SaveIterations();
126+
}
127+
128+
private void SaveIterations()
129+
{
130+
try
131+
{
132+
File.WriteAllText(persistIterationFileName, IterationsTextBox.Text);
133+
}
134+
catch { }
111135
}
112136

113-
private void Save()
137+
private void SaveCode()
114138
{
115139
try
116140
{
117-
File.WriteAllText(persistFileName, ScriptTextBox.Text);
141+
File.WriteAllText(persistCodeFileName, ScriptTextBox.Text);
118142
}
119143
catch { }
120144
}

0 commit comments

Comments
 (0)