如果可以减少嵌套“if”语句,我想重构我的代码,使其更加优雅和清晰。
我的代码“解析”MsBuil进程的任何字符串(结果),以检查进程是否正确构建。
public static bool CheckMsBuildResult(string resultadoEjecucionScriptMsBuild)
{
// Build started 01/09/2010 8:54:07.
string s1 = @"Build Started \d{1,2}/\d\d/\d{4} \d{1,2}:\d\d:\d\d";
//Build started 9/1/2010 10:53:35 AM.
//Build started 9/1/2010 8:42:16 AM.
string s1Mod = @"Build Started \d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d\d:\d\d";
s1 = s1Mod;
string s11 = @"n Generar iniciada a las \d{1,2}/\d\d/\d{4} \d{1,2}:\d\d:\d\d";
// Compilaci�n iniciada a las 28/02/2011 14:56:55.
string s12 = @"Compilaci.n iniciada a las \d{1,2}/\d\d/\d{4} \d{1,2}:\d\d:\d\d";
string s2 = "Build succeeded.";
string s21 = @"Generaci.n satisfactoria\.";
string s3 = @"0 Error\(s\)";
string s31 = "0 Errores";
Regex rg = new Regex(s1, RegexOptions.Multiline | RegexOptions.IgnoreCase);
Match mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
rg = new Regex(s11, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
rg = new Regex(s12, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success) return false;
}
}
int i = mt.Index + mt.Length;
rg = new Regex(s2, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild, i);
if (!mt.Success)
{
rg = new Regex(s21, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
return false;
}
}
i = mt.Index + mt.Length;
rg = new Regex(s3, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild, i);
if (!mt.Success)
{
rg = new Regex(s31, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
return false;
}
}
return true;
}
答案 0 :(得分:5)
看起来你可以通过使用一个更强大的正则表达式而不是s1
,s1mod
,s12
等来将其减少到一行或两行代码。但是,既然你已经修改了你的正则表达式,我无法确切地告诉你它的样子。
我也批评这段代码
答案 1 :(得分:1)
我认为你可以在这里减少很多重复的代码。
编辑(删除了一些重复的代码并发布了linq方法):
public static Match MatchOptions(string resultadoEjecucionScriptMsBuild, int index, params string[] strings)
{
return strings.Select(s => new Regex(s, RegexOptions.Multiline | RegexOptions.IgnoreCase))
.Select(rg => rg.Match(resultadoEjecucionScriptMsBuild, index)).FirstOrDefault(mt => mt != null);
}
或者如果你不喜欢linq:
public static Match MatchOptions(string resultadoEjecucionScriptMsBuild, int index, params string[] strings)
{
foreach (string s in strings)
{
Regex rg = new Regex(s, RegexOptions.Multiline | RegexOptions.IgnoreCase);
Match mt = rg.Match(resultadoEjecucionScriptMsBuild, index);
if (mt != null)
return mt;
}
return null;
}
public static bool CheckMsBuildResult(string resultadoEjecucionScriptMsBuild)
{
string s1 = @" ..... ";
string s1Mod = @" ..... ";
string s11 = @" ..... ";
// Compilaci�n iniciada a las 28/02/2011 14:56:55.
string s12 = @" ..... ";
string s2 = @" ..... ";
string s21 = @" ..... ";
string s3 = @" ..... ";
string s31 = @" ..... ";
var stringsArray = new[]
{
new[] {s1, s11, s12},
new[] {s2, s21},
new[] {s3, s31}
};
Match mt = null;
int i = 0;
foreach (string[] strings in stringsArray)
{
mt = MatchOptions(resultadoEjecucionScriptMsBuild, i, strings);
if (mt == null)
return false;
i = mt.Index + mt.Length;
}
return mt != null;
}
答案 2 :(得分:1)
以下是两个想法:
您似乎正在尝试使用嵌套if
对decision tree进行编码。一个更好的选择可能是定义一个对树进行编码的数据结构,然后以递归方式遍历树以测试匹配。
我认为没有任何简单的方法可以重构代码以避免嵌套。如果你足够勇敢,可以使用LINQ语法。 (我的free chapter中有一个functional programming book解释 monads 如何工作以及如何使用LINQ编写这样的东西。
使用LINQ语法,您可以重写:
Regex rg = new Regex(s1, RegexOptions.Multiline | RegexOptions.IgnoreCase);
Match mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
rg = new Regex(s11, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success)
{
rg = new Regex(s12, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild);
if (!mt.Success) return false;
}
}
......变成这样的东西(注意你需要定义相当多的帮助器而我没有显示完整的代码 - 所以你无法比较长度 - 但你可以看到它避免了嵌套):
var matches =
from rg1 in MatchRegex(s1, RegexOptions.Multiline | RegexOptions.IgnoreCase,
resultadoEjecucionScriptMsBuild)
from rg2 in MatchRegex(s11, RegexOptions.Multiline | RegexOptions.IgnoreCase,
resultadoEjecucionScriptMsBuild)
from rg3 in MatchRegex(s11, RegexOptions.Multiline | RegexOptions.IgnoreCase,
resultadoEjecucionScriptMsBuild)
select true;
if (matches) return false;
如果您需要访问某些早期Match
对象以确定最终结果(例如,最后使用rg1
),这可能很有用。否则,您可能只需编写一个运行给定正则表达式的方法,并使用if
将它们组合在一个大的&&
语句中。
答案 3 :(得分:1)
第一个重构变量名。然后尝试使用布尔值展平代码,如下例所示:
Regex rg = new Regex(s1, RegexOptions.Multiline | RegexOptions.IgnoreCase);
bool match_s1 = rg.Match(resultadoEjecucionScriptMsBuild).Success;
rg = new Regex(s11, RegexOptions.Multiline | RegexOptions.IgnoreCase);
bool match_s11 = rg.Match(resultadoEjecucionScriptMsBuild).Success;
rg = new Regex(s12, RegexOptions.Multiline | RegexOptions.IgnoreCase);
bool match_s12 = rg.Match(resultadoEjecucionScriptMsBuild).Success;
if (!match_s1 && !match_s11)
return match_s12;
答案 4 :(得分:0)
如果输入包含s1|s11|s12
之一,后跟s2|s21
之一,最后是s3|s31
之一,则您似乎要测试。
你总是可以制作一个更复杂的正则表达式来反映这一点:
var complex = "((" + s1 + ")|(" + s11 + ")|(" + s12 + "))|((" + s2 + ")|(" + s21 + ...
并在一场比赛中使用它。
如果你只是想摆脱嵌套的ifs(即如果你想要一个维持当前控制流的重构),我会将正则表达式分组到像
这样的列表中var reList = new List<List<string>>() {
new List<string>(){s1, s11, s12},
new List<string>(){s2, s21},
new List<string>(){s3, s31}
};
(使用C#3.0集合初始值设定项)
然后你可以迭代两个嵌套循环中的所有表达式,比如
var i = 0;
foreach (var outer in reList) {
Match mt;
foreach (var inner in outer) {
rg = new Regex(inner, RegexOptions.Multiline | RegexOptions.IgnoreCase);
mt = rg.Match(resultadoEjecucionScriptMsBuild, i);
if (mt.Success)
break;
}
if (!mt.Success)
return false;
i = mt.Index + mt.Length;
}
return true;
如果输入字符串是s1,s11,s12
之一,s2, s21
之一,最后是s3, s31
之一的串联,则此函数返回true。