【问题标题】:Using Regex Array with String Array将正则表达式数组与字符串数组一起使用
【发布时间】:2017-08-08 17:00:41
【问题描述】:

我正在尝试制作一个程序,用户可以在其中输入一系列序列号并显示每个相应的产品。

假设我知道产品 A 总是以“C02”开头,产品 B 总是以“X02”结尾,而产品 C 总是包含“A1700”。那么如果用户输入的是“C02HGV32,N93XA1700D,J3429X02”,则返回“C02HGV32:产品A;N93XA1700D:产品C;J3429X02:产品B”。

如何获得一组正则表达式来与字符串数组进行比较?这是我所拥有的:

using System.Text.RegularExpressions;
public class ReturnProduct{
    public Regex[] compareAgainst = new Regex[3]{@"[C02]*",@"*[X02]",@"*[A1700]*"}; //Clearly not the right way, but not sure how else to do it

...

public string getTheProduct(string input){
string[] compareString = input.Split(",");
for (int a = 0; a < compareString.Length; a++){
    for (int b = 0; b < compareAgainst.Length; b++){
        //Do something Regex-y with compareString[a] and compareAgainst[b]
    }
}

【问题讨论】:

  • 您是否要求正确的正则表达式语法?或者如何检查字符串是否匹配正则表达式?
  • 我正在询问正则表达式数组的正确语法,以及如何根据每个正则表达式数组值检查每个字符串值 - 抱歉,不清楚。
  • 我没有投反对票,但“这到底是如何工作的?”不是一个明确的问题。我不会认为您因“试图尽可能多地解释”而被否决。
  • 我想我应该为此使用分号 - “这到底是如何工作的?”与上一句有关。烂英文。我现在已经更新了。

标签: c# arrays regex


【解决方案1】:

如果这些代码的要求如此简单,您可以使用String.ContainsString.StartsWithString.EndsWith。您可以创建一个Dictionary 来保存产品名称和函数,以检查给定字符串是否具有产品的模式。

var dict = new Dictionary<string, Predicate<string>>
{
    ["Product A"] = s => s.StartsWith("C02"),
    ["Product B"] = s => s.EndsWith("X02"),
    ["Product C"] = s => s.Contains("A1700")
};

string GetProductName(string serialNum)
{
    foreach(var keyVal in dict)
    {
        if(keyVal.Value(serialNum))
            return keyVal.Key;
    }

    return "No product name found";
}

List<(string, string)> GetProductNames(string str)
{
    var productCodes = str.Split(',');
    var productNames = new List<(string, string)>(); // list of tuples (string, string)

    foreach(var serialNum in productCodes)
    {
        productNames.Add((serialNum, GetProductName(serialNum)));
    }

    return productNames;
}

用法:

var userString = "C02HGV32,N93XA1700D,J3429X02";
List<(string serialNum, string name)> productNames = GetProductNames(userString);
foreach(var tuple in productNames)
{
    Console.WriteLine($"{tuple.serialNum} : {tuple.name}");
}

如果你特别想使用 Regex,可以使用以下模式:

var regexDict = new Dictionary<string, Regex>
{
    ["Product A"] = new Regex("^C02"), //'^' means beginning of string
    ["Product B"] = new Regex("X02$"), //'$' means end of string
    ["Product C"] = new Regex("A1700") //given string anywhere
};

string GetProductName(string serialNum)
{
    foreach(var keyVal in regexDict)
    {
        if(keyVal.Value.IsMatch(serialNum))
            return keyVal.Key;
    }

    return "No product name found";
}

List<(string, string)> GetProductNames(string str)
{
    var productCodes = str.Split(',');
    var productNames = new List<string>();

    foreach(var serialNum in productCodes)
    {
        productNames.Add((serialNum, GetProductName(serialNum)));
    }

    return productNames;
}

【讨论】:

  • 完美,谢谢!虽然有大约 2600 种产品,但我有点希望不必使用字典。 ://
  • 字典很快,它们在内部使用散列,但我不知道你关心的是速度还是内存使用
  • 我打算让产品名称的字符串数组和序列号搜索的 Regex 数组的顺序相同,所以如果输入匹配 Regex 数组的 [n],它会简单地返回[n] 的字符串数组。我猜这将是迄今为止最快的,因为我认为简单地访问数组将是 O(1)。我还认为那将是最少的记忆。
  • 您仍然需要遍历数组,并且遍历字典对程序来说并没有更多的工作。只有当您找到产品或找不到任何东西时,您才会停下来,所以这是一样的。字典还使用几个数组来保存项目(并且可以动态调整大小),因此使用的内存不会比你有一个数组大很多
  • 好吧,这是有道理的。谢谢你的解释!
【解决方案2】:

为您的产品定义一个类:

public class Product
{
    public string Name { get; set; }
    public Regex Expr { get; set; }
}

然后创建一个包含所有正则表达式的数组:

var regexes = new[]
{
    new Product
    {
        Name = "Product A",
        Expr = new Regex("^C02")
    },
    new Product
    {
        Name = "Product B",
        Expr = new Regex("X02$")
    },
    new Product
    {
        Name = "Product C",
        Expr = new Regex("A1700")
    }
};

现在您可以使用LINQ 查询:

var input = "C02HGV32,N93XA1700D,J3429X02";
var result = string.Join("; ",
    input.Split(',')
    .Select(s => new {regexes.FirstOrDefault(p => p.Expr.IsMatch(s))?.Name, Value = s})
    .Select(x => $"{x.Value}: {x.Name}"));

result 会是

C02HGV32:产品A; N93XA1700D:产品C; J3429X02:产品 B

【讨论】:

    【解决方案3】:

    正则表达式语法:

    • "^C02.*" - 以 C02 开头,后跟任意数量的字符,包括 0 个字符。
    • "^.*X02" - 以任意数量的字符开头,包括 0 个字符,并以 X02 结尾。
    • "^.A1700.*" - 以任意数量的字符开始和结束,并且在某处包含 A1700。

      public static void GetTheProduct(string input, List<Regex> regList)
      {
          List<string> compareString = input.Split(new char[] { ',' }).ToList();
          foreach (string item in compareString)
          {
              if (regList[0].Match(item).Success)
                  Console.WriteLine("{0} : {1}", item, "Product A");
              else if (regList[1].Match(item).Success)
                  Console.WriteLine("{0} : {1}", item, "Product B");
              else if (regList[2].Match(item).Success)
                  Console.WriteLine("{0} : {1}", item, "Product C");
          }
      }
      
      static void Main(string[] args)
      {
          List<Regex> regexList = new List<Regex>() { new Regex("^C02.*"), new Regex("^.*X02"), new Regex("^.*A1700.*") };
          GetTheProduct("C02HGV32,N93XA1700D,J3429X02", regexList);
          Console.ReadLine();
      }
      

    您还可以概括该方法并避免对产品名称进行硬编码。 像这样:

        public static void GetTheProduct(string input, Dictionary<string, Regex> regDictionary)
        {
            List<string> compareString = input.Split(new char[] { ',' }).ToList();
            foreach (string item in compareString)
            {
                string key = regDictionary.First(x => x.Value.IsMatch(item)).Key;
                Console.WriteLine("{0} : {1}", item, key);
            }
        }
    
        static void Main(string[] args)
        {
            Dictionary<string, Regex> regDictionary = new Dictionary<string, Regex>();
            regDictionary.Add("Product A", new Regex("^C02.*"));
            regDictionary.Add("Product B", new Regex("^.*X02"));
            regDictionary.Add("Product C", new Regex("^.*A1700.*"));
    
            GetTheProduct("C02HGV32,N93XA1700D,J3429X02", regDictionary);
            Console.ReadLine();
        }
    

    【讨论】:

    • 请注意,^.*X02 并不意味着以任何结尾。没有理由过度杀死匹配,因为正则表达式默认在字符串内搜索匹配:A1700 足以包含“A1700”。 ^C02 足以以“C02”开头。
    猜你喜欢
    • 2016-06-17
    • 2012-04-26
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多