我有一个字符串和多个正则表达式,例如一个正则表达式,它检查字符串是否只是一个数字,如果它以字符X开头,依此类推。我有不同的代码运行,具体取决于正则表达式匹配,如下所示:
if (Regex.IsMatch(myString, regex1))
{
//number
}
else if (Regex.IsMatch(myString, regex2))
{
//something else
}
else if (Regex.IsMatch(myString, regex3))
{
//something else
}
等等。然而,这看起来非常笨重,因为我喜欢10个正则表达式,所以我可以使用开关/案例做同样的事情吗?如果是这样,我可以提供一个例子吗?
我正在使用.NET 2.0和WinForms。
答案 0 :(得分:2)
你可以保存一个关联字典 - 匹配函数和处理逻辑,然后只需循环匹配,一旦它返回true - 执行相关的处理逻辑,这样你最终会得到非常简单的foreach
循环:
string input = "some input ^&(*729384293";
string numberPattern = "regex to check numbers";
string datePattern = "regex to check date";
// KEY - match regex function
// VALUE - match handling logic
var matchesMap = new Dictionary<Func<bool>, Action>();
matchesMap.Add(
() => Regex.IsMatch(input, numberPattern),
() => { /*this code will be called when numer match found*/ });
matchesMap.Add(
() => Regex.IsMatch(input, datePattern),
() => { /*this code will be called when date match found*/ });
foreach (var match in matchesMap.Keys)
{
if (match())
{
matchesMap[match].Invoke();
break;
}
}
答案 1 :(得分:1)
这不能像你描述的那样完成,因为switch只能用于:bool,char string,int,enum或相应的可空类型。
答案 2 :(得分:1)
执行此操作的唯一方法是使用switch-true语句(不推荐)。
switch (true)
{
case Regex.IsMatch(myString, regex1):
// ...
break;
case Regex.IsMatch(myString, regex2):
// ...
break;
case Regex.IsMatch(myString, regex3):
// ...
break;
default:
// ...
break;
}
编辑: Buh Buh提到了case表达式必须是常量的事实,因此代码不会编译。
还有另一种非常迂回的方法来解决这个问题。请记住,我指出这不是建议,而是作为if块更好的原因的一个例子。
如果您的正则表达式位于数组regexes
中,则可以执行以下操作:
int type = -1;
for (int i = 0; i < regexes.Length; i++)
{
if (Regex.IsMatch(myString, regexes[i])
{
type = i;
break;
}
}
switch (type)
{
case 0:
// ...
break;
case 1:
// ...
break;
case 2:
// ...
break;
default:
break;
}
答案 3 :(得分:1)
你可以制作一个更复杂的正则表达式,如/(a)|(b)|(c)/然后检查match.Groups,之后匹配的模式:
Match match = Regex(input, @"/(a)|(b)|(c)/");
Foreach (Group g in match.Groups) {
if (g.Success) {
// Your code here
}
}
答案 4 :(得分:1)
一个'非笨重'的解决方案是使用Chain Of Responsibility设计模式的简化版本。事实上,这种模式是为了处理大卫在这里描述的情况。
在您的情况下,您只需要将字符串映射到活动。您可以定义一个基类 迭代链并在找到匹配时执行定义的活动,或者将输入转发到下一个选项。
abstract class Option
{
public void DoActivity(string input)
{
Match parse = m_regex.Match(input);
if (parse.Success)
Activity(input);
else if (m_nextOption != null)
m_nextOption.DoActivity(input);
else
Console.WriteLine("No activity for input \"{0}\"", input);
}
// Each option defines its own activity; override as necessary.
protected void Activity(string input)
{
Console.WriteLine(
"For input \"{0}\" --> do activity defined in {1} ...", input, this);
}
// The next option in the chain, or null.
protected Option m_nextOption;
// Regular expression that matches the input for this option.
protected Regex m_regex;
}
然后根据需要为多个选项创建派生类。每个定义:
类似的东西:
internal class OptionOne : Option
{
public OptionOne()
{
m_nextOption = new OptionTwo(); // next option.
m_regex = new Regex(@"^Option One$", RegexOptions.Compiled);
}
}
internal class OptionTwo : Option
{
public OptionTwo()
{
m_nextOption = new OptionThree(); // next option.
m_regex = new Regex(@"^Option Two$", RegexOptions.Compiled);
}
}
internal class OptionThree : Option
{
public OptionThree()
{
m_nextOption = null; // no other options.
m_regex = new Regex(@"^Option Three$", RegexOptions.Compiled);
}
}
// Possible input strings.
string[] myStrings = { "Option One", "Option Two",
"Option Three", "Matches No Options" };
// Do each input's activity ...
Option options = new OptionOne();
foreach (var myString in myStrings)
{
options.DoActivity(myString);
}
输入“选项一” - &gt;在StackOverflow.OptionOne中定义活动...
对于输入“选项二” - &gt;在StackOverflow.OptionTwo中定义的活动...
输入“选项三” - &gt;在StackOverflow.OptionThree中定义活动...
没有输入活动“匹配无选项”
使用此模式的另一个好处是,如果以后需要添加其他选项,则只需定义其他派生类并将其挂钩到链中。调用代码根本不需要改变!
答案 5 :(得分:1)
归结为每个Regex案例的代码量。
如果它只是一行或两行代码
我说坚持使用if-else。它不仅更直接,更直观,而且更容易阅读。
如果它很复杂,或者您多次使用开关
如果您拥有的内容相当复杂,您可能需要考虑实施战略模式或类似的东西。
有时候switch语句很好,但是当你发现自己多次使用同一个开关,或者每种情况都有大量的代码时,策略模式可以真正有所帮助,特别是在可维护性方面