C# 将分隔宽度转换为固定宽度的最佳方法

C# 将分隔宽度转换为固定宽度的最佳方法,c#,linq,C#,Linq,转换此项的最佳方法是什么: 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-

转换此项的最佳方法是什么:

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
为此:

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

我会创建一个自定义类来保存信息,然后对CSV文件中的每一行进行循环,用逗号分割并填充自定义对象。然后将它们全部放入列表或IEnumerable中,并将其放入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
        }
    }

我会创建一个自定义类来保存信息,然后对CSV文件中的每一行进行循环,用逗号分割并填充自定义对象。然后将它们全部放入列表或IEnumerable中,并将其放入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
        }
    }

这符合您所述的要求,并使用LINQ,因为您的问题被标记为LINQ,但不一定是最好的:


但在生产场景中,我希望看到这些数据被读取到适当的人员类别中,正如Matt在回答中所建议的那样。

这符合您所述的要求,并且使用LINQ,因为您的问题被标记为LINQ,但不一定是最佳的:

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
    }
}
但在生产场景中,我希望看到这些数据被读入适当的Person类,正如Matt在回答中所建议的那样

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
    }
}

我知道最简单的方法是在PowerShell中:


我知道最简单的方法是在PowerShell中:


这里有两个问题。分开考虑,你会更容易找到一个好的解决方案。

将CSV格式的输入数据解析为有用的格式

以某种方式呈现您的数据

不要编写自己的CSV解析器。规则有点棘手,但格式是众所周知的。从长远来看,弄错它是不好的。在.NET framework中,您可以调用现有的CSV库,但我对它们了解不多。但是,这个问题非常适合C中的新动态特性。下面是一个看起来很有希望的问题:


我假设打印数据是一个小问题,您不需要我们的帮助。如果没有,您需要向我们提供更多信息,例如如何确定列的宽度。

这里有两个问题。分开考虑,你会更容易找到一个好的解决方案。

将CSV格式的输入数据解析为有用的格式

以某种方式呈现您的数据

不要编写自己的CSV解析器。规则有点棘手,但格式是众所周知的。从长远来看,弄错它是不好的。在.NET framework中,您可以调用现有的CSV库,但我对它们了解不多。但是,这个问题非常适合C中的新动态特性。下面是一个看起来很有希望的问题:

我假设打印数据是一个小问题,您不需要我们的帮助。如果没有,你需要给我们更多的信息,比如你想如何决定列的宽度。

我写这篇文章就是为了这个目的。安装

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 ... 及

我会给你

tablify input.dat
从那里,应该可以很容易地使文件适应您的需要。

我就是为了这个目的而写的。安装

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 ... 及

我会给你

tablify input.dat

从这里开始,应该可以很容易地根据您的需要调整文件。

您所说的“最佳”是指最简洁、最具可读性还是更高的性能?我所说的“最佳”是指在现实场景中有用且灵活。任何一个在这里呆了足够长时间的人都会知道,分隔文件的布局最终会发生变化:你说的最好是指最简洁、最可读还是性能更好?我说的最好是指在现实场景中有用且灵活。任何人都知道分隔文件的布局最终会发生变化:为什么不在ToFixedWidths函数中使用ss.PadRightwidths[i],“”呢?为什么不在ToFixedWidths函数中使用ss.PadRightwidths[i],“”呢?+1,这是一个很好的开始方法,尤其是当您需要验证源文件并捕获可能的数据错误时。但我会让Person类中的Parse方法负责字符串拆分和解析逻辑我不是在问如何将分隔值解析到对象:@ehosca-在对象中一次,尽管您可以使用ToString方法打印整行。编写一个简单的foreach循环来处理打印。您的代码如何处理对Fuller先生的标题的解析@埃霍斯卡——实际上,这完全取决于你想做多少工作。您是否偶然建立了导入流程?我以前做过Outlook/Outlook Express的导入功能,它们都以不同的方式导出联系人列表!。因此Outlook将提供此人的标题,但对于Outlook,将提供标题。我的解决方案是做一个小的正则表达式检查来测试名字,如果是阳性的话,将其提取出来。我甚至有两个人的名字,约翰和克里·斯科特。这不是一项容易的任务,但也不是不可能的。良好的学习经验/挑战+1,这是一个很好的开始方法,特别是当您需要验证源文件并捕获可能的数据错误时。但我会
d在Person类中使用Parse方法负责字符串拆分和解析逻辑我不是在问如何将分隔值解析到对象:@ehosca-在对象中使用一次,尽管您可以使用ToString方法打印整行。编写一个简单的foreach循环来处理打印。您的代码如何处理对Fuller先生的标题的解析@埃霍斯卡——实际上,这完全取决于你想做多少工作。您是否偶然建立了导入流程?我以前做过Outlook/Outlook Express的导入功能,它们都以不同的方式导出联系人列表!。因此Outlook将提供此人的标题,但对于Outlook,将提供标题。我的解决方案是做一个小的正则表达式检查来测试名字,如果是阳性的话,将其提取出来。我甚至有两个人的名字,约翰和克里·斯科特。这不是一项容易的任务,但也不是不可能的。良好的学习经验/挑战!我完全同意你的观点。dynamic看起来确实很有前途。当我们为4.0开绿灯时,我肯定会考虑到这一点。我在编写SQL查询分析器类型的工具时遇到了这个问题,该工具允许您针对GemFire分布式缓存编写OQL查询并显示结果,而不是使用数据库。查询分析器允许在多个视图、网格中以文本等形式显示输出。我猜他在制定问题方面做得不够好。确定列宽的规则是:列中任何单个项目的最宽宽度+1我同意你的所有观点。dynamic看起来确实很有前途。当我们为4.0开绿灯时,我肯定会考虑到这一点。我在编写SQL查询分析器类型的工具时遇到了这个问题,该工具允许您针对GemFire分布式缓存编写OQL查询并显示结果,而不是使用数据库。查询分析器允许在多个视图、网格中以文本等形式显示输出。我猜他在制定问题方面做得不够好。确定列宽的规则是:列中任何单个项的最宽宽度+1我希望看到-AutoSize选项的实现:我希望看到-AutoSize选项的实现: