简体   繁体   中英

Formatting a string of numbers depedning on length

In my model I have a cNumber string, which can be different length (16,24 and 28), and I need to format it accordingly in my view in the table.

  16 length: ########-########
  24 : ########-########-########
  28 : #### #### #### #### #### #### ####

UPDATE: I do have a method for the formatting, but I had a hard time passing it to the view to show up at the correct record of the table.

        static string Format(string cNumber)
        {
            
            if (cNumber.Length == 16 || cNumber.Length == 24)
            {
                cNumber= Regex.Replace(cNumber, ".{8}", "$0-");
            }
            else if (cNumber.Length == 28)
            {
                cNumber= Regex.Replace(cNumber, ".{4}", "$0 ");
            }
            else
            {
                return cNumber;
            }

            cNumber= cNumber.Remove(cNumber.Length - 1);

            return cNumber;
        }

        
        public ActionResult Index(Guid id)
        {
            var PartnerCNumbers = db.PartnerCNumbers.Include(p => p.Partner).Where(p=>p.Partner.PartnerGuid == id);

            

            var cNumList = new List<string>();

            foreach (var cn in PartnerCNumbers)
            {
                cNumList.Add(Format(cn.cNumber));
            }

            
            ViewData["cNumbers"] = cNumList;
            ViewBag.PartnerGuid = id;
         

            return View(PartnerCNumbers.ToList());
        }

In my view i have the ViewData as a list

@model IEnumerable<Models.PartnerCNumbers>

IEnumerable<string> cNumbers= ViewData["cNumbers"] as IEnumerable<string>;

@foreach (var item in Model)
        {
            //int cLength = item.cNumber.Length;

            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Currency)
                </td>
                <td>
                    //@Html.DisplayFor(modelItem => item.cNumber)
                    //THIS IS WHERE I NEED THE FORMATTED cNUMBER
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.sCode)
                </td>
            </tr>
}

Which is the best way to do it? I tried String.Format() in the view itself, but I couldn't convert it since it's already stored as a string in the database. Can a ViewModel have different annotations depending on a length attribute for example? Or is it somehow possible with javascript

I would create an Extension method for this type of "custom ToString"

public static class CNumberExtensions
{
    static string ToFormattedCNumber(this string cNumber)
    {
        switch (cNumber.Length)
        {
            case 16:
                return cNumber.Substring(0, 8) + "-"
                     + cNumber.Substring(8);
            case 24:
                return cNumber.Substring(0, 8) + "-"
                     + cNumber.Substring(8, 8) + "-"
                     + cNumber.Substring(16);
            case 28:
                return cNumber.Substring(0, 4) + " "
                     + cNumber.Substring(4, 4) + " "
                     + cNumber.Substring(8, 4) + " "
                     + cNumber.Substring(12, 4) + " "
                     + cNumber.Substring(16, 4) + " "
                     + cNumber.Substring(20, 4) + " "
                     + cNumber.Substring(24);
        }
        throw new ArgumentException("cNumber length can only be 16, 24 or 28", nameof(cNumber));
    }
}

Unless you are calling the function thousands of times per second, "the fastest way" is not necessarily the best.

You can use the following helper function in C# to format input strings by length as your requirement:

class Program
{
    static string formatByLength(string s)
    {
        if (s.Length == 16)
        {
            return s.Substring(0, 8) + "-" + s.Substring(8);
        }
        if (s.Length == 24)
        {
            return s.Substring(0, 8) + "-" + s.Substring(8, 8) + "-" + s.Substring(16);
        }
        if (s.Length == 28)
        {
            var sb = new System.Text.StringBuilder();
            for (var i = 0; i < 7; i++)
            {
                if (sb.Length > 0)
                {
                    sb.Append(" ");
                }
                sb.Append(s.Substring(i * 4, 4));
            }
            return sb.ToString();
        }

        // return original string
        return s;
    }

    static void Main(string[] args)
    {
        Console.WriteLine(formatByLength("1234567890123456"));
        Console.WriteLine(formatByLength("123456789012345678901234"));
        Console.WriteLine(formatByLength("1234567890123456789012345678"));
    }
}

It outputs the following result:

12345678-90123456
12345678-90123456-78901234
1234 5678 9012 3456 7890 1234 5678

I would build a method to take a length of string with n fixed-length segments and then insert delimiters between:

private static string FormatNumberString(string input, int segmentLength, char delimiter)
{
    StringBuilder builder = new StringBuilder();
    // In a 16-length string, i will initially be 0, and then on the next
    // iteration of the loop it will be 8
    for (int i = 0; i < input.Length; i += segmentLength)
    {
        // if we're just starting another block we should add the delimiter
        if (i != 0)
        {
            builder.Append(delimiter);
        }

        // add the section from i to i + segmentLength (e.g. 0-7 and then 8-15)
        builder.Append(input.Substring(i, segmentLength));
    }
    return builder.ToString();
}

Then we can make a method to make calling this one easier:

private static string FormatNumberStringByLength(string input)
{
    switch (input.Length)
    {
        // given the method above, 16 and 24-length strings have the same
        // run length and delimiter, so we can group these together
        case 16:
        case 24:
            return FormatNumberString(input, 8, '-');
        case 28:
            return FormatNumberString(input, 4, ' ');
        default:
            throw new ArgumentException("Input string length not recognized.", nameof(input));
    }
}

Usage:

Console.WriteLine(FormatNumberStringByLength("1234567812345678"));
Console.WriteLine(FormatNumberStringByLength("123456781234567812345678"));
Console.WriteLine(FormatNumberStringByLength("1234123412341234123412341234"));

Try it online

You should use cNumbers instead of the Model in the foreach loop.

IEnumerable<string> cNumbers= ViewData["cNumbers"] as IEnumerable<string>;

@foreach (var cNumber in cNumbers)
{
            <tr>
                <td>
                    //other model data
                </td>
                <td>
                   @cNumber
                </td>
                <td>
                    //other model data
                </td>
            </tr>
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM