解析自定义数据令牌并替换为C#中的值

时间:2011-05-06 20:27:01

标签: c# regex lexer parser-generator

我从记录中获得了大约10个数据,我希望能够定义返回此数据的字符串的布局,并可以选择保留一些部分。我的想法是使用枚举为我的标记/字段提供整数值,然后使用{0}{1}{2}{3}之类的格式或像{4} - {3}{1} [{8}]那样复杂的格式。令牌的含义与我的数据库中的字段有关。例如,我有关于付款的令牌的这个枚举。

AccountMask = 0,
AccountLast4 = 1,
AccountFirstDigit = 2,
AccountFirstLetter = 3,
ItemNumber = 4,
Amount = 5

帐户掩码是一个字符串,如VXXXXX1234,其中V代表签证,1234代表该卡的最后4位数字。有时客户想要V,有时他们想要第一个数字(很容易将卡片类型翻译成第一个数字)。

我的目标是创建一个可重用的东西,使用格式字符串中的标记生成字符串,然后使用与标记内部数字相关联的数据来替换数据。

所以,如果我想定义格式9{2}{1}{4:[0:0000000000]}

,请使用上面的掩码和我的枚举的示例

如果料号为678934

然后将转换为9412340000678934,其中令牌4的内部部分成为该值的String.Format的定义。此外,放置在令牌周围的数据将被忽略并保留在原位。

我的问题在于操纵字符串和最佳实践。有人告诉我,如果要动态创建正则表达式可能会很昂贵。作为CS专业,我有一种感觉,“正确”(无论多么复杂)的解决方案是为我的代币制作词法分析器/解析器。我没有在C#中编写词法分析器/解析器的经验,因此我不确定围绕它的最佳实践。我正在寻找有效且易于调整的系统的指导。

2 个答案:

答案 0 :(得分:0)

我看到了这个问题,我立刻认为解决方案非常简单;存储您希望使用的掩码,使用您希望包含的各种数据字段的常量值,并将掩码传递给String.Format()的常量调用:

const string CreditCardWithFirstLetterMask = "{3}XXXXXXXXXXX{1}";
const string CreditCardWithFirstDigitMask = "{2}XXXXXXXXXXX{1}";

...

var formattedString = String.Format(CreditCardWithFirstDigitMask, 
   record.AccountMask,
   record.AccountLast4,
   record.AccountFirstDigit,
   record.AccountFirstLetter,
   record.ItemNumber,
   record.Amount); 

答案 1 :(得分:0)

我最终将正则表达式作为类中的静态对象,然后循环遍历匹配以执行替换并构建我的令牌。

var token = request.TokenFormat;

var matches = tokenExpression.Matches(request.TokenFormat);

foreach (Match match in matches)
{
    var value = match.Value;
    var tokenCode = (Token)Convert.ToInt32(value.Substring(1, (value.Contains(":") ? value.IndexOf(":") : value.IndexOf("}")) - 1));

    object data = null;

    switch (tokenCode)
    {
        case Token.AccountMask:
            data = accountMask;
            break;
        case Token.AccountLast4:
            data = accountMask.Substring(accountMask.Length - 4);
            break;
        case Token.AccountFirstDigit:
            string firstLetter = accountMask.Substring(0, 1);

            switch (firstLetter.ToUpper())
            {
                case "A":
                    data = 3;
                    break;
                case "V":
                    data = 4;
                    break;
                case "M":
                    data = 5;
                    break;
                case "D":
                    data = 6;
                    break;
            }

            break;
        case Token.AccountFirstLetter:
            data = accountMask.Substring(0, 1);
            break;
        case Token.ItemNumber:
            if(item != null)
                data = item.PaymentId;
            break;
        case Token.Amount:
            if (item != null)
                data = item.Amount;
            break;
        case Token.PaymentMethodId:
            if (paymentMethod != null)
                data = paymentMethod.PaymentMethodId;
            break;
    }

    if (formatExpression.IsMatch(value))
    {
        Match formatMatch = formatExpression.Match(value);
        string format = formatMatch.Value.Replace("[", "{").Replace("]", "}");

        token = token.Replace(value, String.Format(format, data));
    }
    else
    {
        token = token.Replace(value, String.Format("{0}", data));
    }
}

return token;