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

发布于 2024-11-05 09:45:45 字数 879 浏览 0 评论 0原文

我有来自一条记录的大约 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 的定义。此外,放置在令牌周围的数据将被忽略并保留在适当的位置。

我的问题涉及字符串的操作和最佳实践。有人告诉我,如果您要即时创建正则表达式,其成本可能会很高。作为一名计算机科学专业的学生,​​我感觉“正确”(尽管复杂)的解决方案是为我的标记创建一个词法分析器/解析器。我没有用 C# 编写词法分析器/解析器的经验,所以我不确定它的最佳实践。我正在寻找有关高效且易于调整的系统的指导。

I have about 10 pieces of data from a record and I want to be able to define the layout of a string where this data is returned, with the option of leaving some pieces out. My thought was to use an enum to give integer values to my tokens/fields and then have a format like {0}{1}{2}{3} or something as complicated as {4} - {3}{1} [{8}]. The meaning of the tokens relates to fields in my database. For instance I have this enum for my tokens relating to payments made.

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

Account mask is a string like VXXXXX1234 where the V is for a visa, and 1234 are the last 4 digits of the card. Sometimes clients wants the V, sometimes they want the first digit (It's easy to translate a card type into a first digit).

My goal is to create something reusable to generate a string using tokens in a format string that will then use the data associated with the digit inside the token to do an in place replace of the data.

So, for an example using the mask above and my enum if I wanted to define a format 9{2}{1}{4:[0:0000000000]}

if the item number is 678934

which would then translate to 9412340000678934 where the inner part of token 4 becomes a definition for a String.Format of that value. Also, the data placed around the tokens is ignored and kept in place.

My issue comes to the manipulation of the string and the best practice. I have been told that regular expressions can be costly if you are going to create them on the fly. As a CS major, I have a feeling the "right" (however complex) solution is to make a lexer/parser for my tokens. I have no experience writing a lexer/parse in C# so I'm not sure of the best practices around it. I'm looking for guidance here on a system that is efficient and easy to tweak.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

岁吢 2024-11-12 09:45:45

看到这个问题,我立刻想到解决办法很简单;存储您希望使用的掩码以及您希望包含的各种数据字段的常量值,并将掩码传递到对 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); 

I see this problem, and I immediately thought that the solution is pretty simple; store the masks you wish to use, with constant values for various data fields you wish to include, and pass the masks into a constant call to 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); 
冷血 2024-11-12 09:45:45

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

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;

I ended up putting the regex as a static object in the class and then looping through matches to perform replacements and build out my token.

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文