开发者

the best way to convert delimited to fixed width

What is the BEST way to convert this :

FirstName,LastName,Title,BirthDate,HireDate,City,Region
Nancy,Davolio,Sa开发者_运维知识库les Representative,1948-12-08,1992-05-01,Seattle,WA
Andrew,Fuller,Vice President Sales,1952-02-19,1992-08-14,Tacoma,WA
Janet,Leverling,Sales Representative,1963-08-30,1992-04-01,Kirkland,WA
Margaret,Peacock,Sales Representative,1937-09-19,1993-05-03,Redmond,WA
Steven,Buchanan,Sales Manager,1955-03-04,1993-10-17,London,NULL
Michael,Suyama,Sales Representative,1963-07-02,1993-10-17,London,NULL
Robert,King,Sales Representative,1960-05-29,1994-01-02,London,NULL
Laura,Callahan,Inside Sales Coordinator,1958-01-09,1994-03-05,Seattle,WA
Anne,Dodsworth,Sales Representative,1966-01-27,1994-11-15,London,NULL

to this :

FirstName  LastName             Title                          BirthDate   HireDate   City            Region
---------- -------------------- ------------------------------ ----------- ---------- --------------- ---------------
Nancy      Davolio              Sales Representative           1948-12-08  1992-05-01  Seattle         WA
Andrew     Fuller               Vice President, Sales          1952-02-19  1992-08-14  Tacoma          WA
Janet      Leverling            Sales Representative           1963-08-30  1992-04-01  Kirkland        WA
Margaret   Peacock              Sales Representative           1937-09-19  1993-05-03  Redmond         WA
Steven     Buchanan             Sales Manager                  1955-03-04  1993-10-17  London          NULL
Michael    Suyama               Sales Representative           1963-07-02  1993-10-17  London          NULL
Robert     King                 Sales Representative           1960-05-29  1994-01-02  London          NULL
Laura      Callahan             Inside Sales Coordinator       1958-01-09  1994-03-05  Seattle         WA
Anne       Dodsworth            Sales Representative           1966-01-27  1994-11-15  London          NULL


I'd create a custom class to hold the information, then do a loop for each line in the CSV file, split on the comma and fill your custom object up. Then throw all of them into a list or IEnumrable and throw it into a repeater / datagrid.

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Title { get; set; }
        public DateTime BirthDate { get; set; }
        public DateTime HireDate { get; set; }
        public string City { get; set; }
        public string Region { get; set; }
    }

    public void Parse(string csv)
    {
        string[] lines = csv.Split( Environment.NewLine.ToCharArray() );
                    List<Person> persons = new List<Person>();

        foreach (string line in lines)
        {
            string[] values = line.Split( ',' );

            Person p = new Person();

            p.FirstName = values[ 0 ];
            p.LastName = values[ 1 ];

                            persons.Add( p );
            //.... etc etc
        }
    }


This meets your requirements as stated, and uses LINQ (since your question was tagged LINQ), but is not necessarily best:

class Program
{
    static void Main(string[] args)
    {
        List<string> inputs = new List<string>
        {
            "FirstName,LastName,Title,BirthDate,HireDate,City,Region",
            "Nancy,Davolio,Sales Representative,1948-12-08,1992-05-01,Seattle,WA",
            "Andrew,Fuller,Vice President Sales,1952-02-19,1992-08-14,Tacoma,WA",
            "Janet,Leverling,Sales Representative,1963-08-30,1992-04-01,Kirkland,WA",
            "Margaret,Peacock,Sales Representative,1937-09-19,1993-05-03,Redmond,WA",
            "Steven,Buchanan,Sales Manager,1955-03-04,1993-10-17,London,NULL",
            "Michael,Suyama,Sales Representative,1963-07-02,1993-10-17,London,NULL",
            "Robert,King,Sales Representative,1960-05-29,1994-01-02,London,NULL",
            "Laura,Callahan,Inside Sales Coordinator,1958-01-09,1994-03-05,Seattle,WA",
            "Anne,Dodsworth,Sales Representative,1966-01-27,1994-11-15,London,NULL"
        };

        // TODO: These widths would presumably be configurable
        List<int> widths = new List<int> { 12, 22, 32, 13, 12, 17, 8 };

        List<string> outputs = inputs.Select(s => ToFixedWidths(s, ',', widths)).ToList();

        outputs.ForEach(s => System.Diagnostics.Debug.WriteLine(s));

        Console.ReadLine();
    }

    private static string ToFixedWidths(string s, char separator, List<int> widths)
    {
        List<string> split = s.Split(separator).ToList();

        // TODO: Error handling - what if there are more/less separators in
        // string s than we have width values?

        return string.Join(String.Empty, split.Select((ss, i) => ss.PadRight(widths[i], ' ')).ToArray());
    }
}

In a production scenario though I'd expect to see this data read into an appropriate Person class, as Matt recommended in his answer.


The easiest way I know to do this is in PowerShell:

PS >  Import-Csv .\x.csv | Format-Table -AutoSize

FirstName LastName Title BirthDate HireDate City Region --------- -------- ----- --------- -------- ---- ------ Nancy Davolio Sales Representative 1948-12-08 1992-05-01 Seattle WA Andrew Fuller Vice President Sales 1952-02-19 1992-08-14 Tacoma WA Janet Leverling Sales Representative 1963-08-30 1992-04-01 Kirkland WA ...


You have two problems here. Consider them separately and you will find a good solution more easily.

  1. Parse your CSV-format input data in to a useful format.

  2. Present your data in a certain way

Don't write your own CSV parser. The rules are a little tricky, but the format is well-known. Getting it wrong would be bad in the long run. There are existing CSV libraries in the .NET framework you could call on, but I don't know much about them. However, this problem is perfect for the new dynamic feature in C#. Here's one that looks promising: http://tonikielo.blogspot.com/2010/01/c-40-dynamic-linq-to-csvhe.html

I'm assuming that printing the data is a trivial problem and you don't need our help. If not, you'll need to give us some more information, like how you want to decide the widths of the columns.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace StringParsingWithLinq
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var inputs = new List<string>
                             {
                                 "FirstName,LastName,Title,BirthDate,HireDate,City,Region",
                                 "Nancy,Davolio,Sales Representative,1948-12-08,1992-05-01,Seattle,WA",
                                 "Andrew,Fuller,\"Vice President, Sales\",1952-02-19,1992-08-14,Tacoma,WA",
                                 "Janet,Leverling,Sales Representative,1963-08-30,1992-04-01,Kirkland,WA",
                                 "Margaret,Peacock,Sales Representative,1937-09-19,1993-05-03,Redmond,WA",
                                 "Steven,Buchanan,Sales Manager,1955-03-04,1993-10-17,London,NULL",
                                 "Michael,Suyama,Sales Representative,1963-07-02,1993-10-17,London,NULL",
                                 "Robert,King,Sales Representative,1960-05-29,1994-01-02,London,NULL",
                                 "Laura,Callahan,Inside Sales Coordinator,1958-01-09,1994-03-05,Seattle,WA",
                                 "Anne,Dodsworth,Sales Representative,1966-01-27,1994-11-15,London,NULL"
                             };

            Console.Write(FixedWidthHelper.ReadLines(inputs)
                              .ToFixedLengthString());
            Console.ReadLine();
        }

        #region Nested type: FixedWidthHelper

        public class FixedWidthHelper
        {
            private readonly Regex _csvRegex = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
            private readonly List<string[]> _data = new List<string[]>();
            private List<int> _fieldLen;

            public static FixedWidthHelper ReadLines(List<string> lines)
            {
                var fw = new FixedWidthHelper();
                lines.ForEach(fw.AddDelimitedLine);
                return fw;
            }

            private void AddDelimitedLine(string line)
            {
                string[] fields = _csvRegex.Split(line);

                if (_fieldLen == null)
                    _fieldLen = new List<int>(fields.Select(f => f.Length));

                for (int i = 0; i < fields.Length; i++)
                {
                    if (fields[i].Length > _fieldLen[i])
                        _fieldLen[i] = fields[i].Length;
                }

                _data.Add(fields);
            }

            public string ToFixedLengthString()
            {
                var sb = new StringBuilder();
                foreach (var list in _data)
                {
                    for (int i = 0; i < list.Length; i++)
                    {
                        sb.Append(list[i].PadRight(_fieldLen[i] + 1, ' '));
                    }
                    sb.AppendLine();
                }

                return sb.ToString();
            }
        }

        #endregion
    }
}

the best way to convert delimited to fixed width


I just wrote tablify for this exact purpose. Install with

[sudo -H] pip3 install tablify

and

tablify input.dat

will give you

FirstName , LastName  , Title                    , BirthDate  , HireDate   , City     , Region
Nancy     , Davolio   , Sales Representative     , 1948-12-08 , 1992-05-01 , Seattle  , WA
Andrew    , Fuller    , Vice President Sales     , 1952-02-19 , 1992-08-14 , Tacoma   , WA
Janet     , Leverling , Sales Representative     , 1963-08-30 , 1992-04-01 , Kirkland , WA
Margaret  , Peacock   , Sales Representative     , 1937-09-19 , 1993-05-03 , Redmond  , WA
Steven    , Buchanan  , Sales Manager            , 1955-03-04 , 1993-10-17 , London   , NULL
Michael   , Suyama    , Sales Representative     , 1963-07-02 , 1993-10-17 , London   , NULL
Robert    , King      , Sales Representative     , 1960-05-29 , 1994-01-02 , London   , NULL
Laura     , Callahan  , Inside Sales Coordinator , 1958-01-09 , 1994-03-05 , Seattle  , WA
Anne      , Dodsworth , Sales Representative     , 1966-01-27 , 1994-11-15 , London   , NULL

From there, it should be easy to adapt the file to your needs.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜