将 CSV 字符串解析为整数数组

Posted

技术标签:

【中文标题】将 CSV 字符串解析为整数数组【英文标题】:Parse CSV string into Array of Integers 【发布时间】:2010-12-18 02:04:23 【问题描述】:

我有一个文本框字段输入 123,145,125 I 来将该字段分隔成一个整数数组。如果一切都正确解析,则验证此字段的真假。

代码:

private bool chkID(out int[] val) 

    char[] delimiters = new char[]  ',' ;
    string[] strSplit = iconeID.Text.Split(delimiters);  


    int[] intArr = null;
    foreach (string s in strSplit) //splits the new parsed characters 
    
        int tmp;
        tmp = 0;
        if (Int32.TryParse(s, out tmp))
        
            if (intArr == null)
            
                intArr = new int[1];
            
            else
            
                Array.Resize(ref intArr, intArr.Length + 1);
            
            intArr[intArr.Length - 1] = tmp;
        

        if (Int32.TryParse(iconeID.Text, out tmp))
        
            iconeID.BorderColor = Color.Empty;
            iconeID.BorderWidth = Unit.Empty;

            tmp = int.Parse(iconeID.Text);
            val = new int[1];
            val[0] = tmp;
            return true;
        


    
    val = null;
    ID.BorderColor = Color.Red;
    ID.BorderWidth = 2;
    return false;

//新代码: private bool chkID(out int[] val) //checkID 函数的布尔值 string[] split = srtID.Text.Split(new char[1] ','); 列表编号 = new List(); int 已解析;

        bool isOk = true;
        foreach( string n in split)
            if(Int32.TryParse( n , out parsed))
                numbers.Add(parsed);
            else
                isOk = false;
        
        if (isOk)
            strID.BorderColor=Color.Empty;
            strID.BorderWidth=Unit.Empty;
            return true;
         else
            strID.BorderColor=Color.Red;
            strID.BorderWidth=2;
            return false;
        
            return numbers.ToArray();
        

【问题讨论】:

告诉我们您当前的代码有什么问题是个好主意。 它是什么语言。我猜是 C#,但那是因为我知道它不是 Java。 我遇到的问题是我需要在文本字段中下载给定 ID 的 XML 数据。例如:“123,456,789”将此 CSV 字符串解析为整数数组,验证字段,然后下载有效 ID 的 XML 数据,谢谢 Chad 【参考方案1】:

给定的函数似乎做的太多了。这是回答您标题暗示的问题的答案:

//int[] x = SplitStringIntoInts("1,2,3, 4, 5");

static int[] SplitStringIntoInts(string list)

    string[] split = list.Split(new char[1]  ',' );
    List<int> numbers = new List<int>();
    int parsed;

    foreach (string n in split)
    
        if (int.TryParse(n, out parsed))
            numbers.Add(parsed);
    

    return numbers.ToArray();

编辑(根据您对问题的评论)

你已经定义了这个函数需要做的三件事。现在你只需要为每个创建方法。以下是我对如何实现它们的猜测。

int[] ValidateIDs(int[] allIDs)

    List<int> validIDs = new List<int>(allIDs);

    //remove invalid IDs

    return validIDs.ToArray();


void DownloadXmlData(int[] ids)

    ...

现在您只需执行新功能:

void CheckIconeID(string ids)

    int[] allIDs = SplitStringIntoInts(ids);
    int[] validIDs = ValidateIDs(allIDs);

    DownloadXmlData(validIDs);

【讨论】:

【参考方案2】:

我真的很想评论@Austin Salonen 的回答,但不合适。对于所提出的问题,这是一个很好的答案,但我想在 csv/int 转换部分更广泛地展开讨论。

这是一个小问题,不值得争论,但我会考虑将foreach 循环换成一个普通的for 循环。您最终可能会得到更简单的 IL(阅读速度更快)。请参阅(http://www.codeproject.com/KB/cs/foreach.aspx、http://msdn.microsoft.com/en-us/library/ms973839.aspx [使用 For 循环进行字符串迭代——版本 1])。 我将创建两种方法——一种是安全的,使用TryParse 并且只添加“好”值,另一种不太安全,但速度更快。

提议的“安全”函数(如果您不想知道坏值,则使用重载)...

    public static int[] SplitAsIntSafe (this string csvString) 
        List<string> badVals;
        return SplitAsIntSafe(csvString, ',', out badVals);
    
    public static int[] SplitAsIntSafe (this string delimitedString, char splitChar, out List<string> badVals) 
        int         parsed;
        string[]    split   = delimitedString.Split(new char[1]  ',' );
        List<int>   numbers = new List<int>();
        badVals             = new List<string>();

        for (var i = 0; i < split.Length; i++) 
            if (int.TryParse(split[i], out parsed)) 
                numbers.Add(parsed);
             else 
                badVals.Add(split[i]);
            
        
        return numbers.ToArray();
    

提议的“快速”功能 ....

    public static int[] SplitAsIntFast (this string delimitedString, char splitChar) 
        string[]    strArray = delimitedString.Split(splitChar);
        int[]       intArray = new int[strArray.Length];

        if(delimitedString == null) 
            return new int[0];
        
        for (var i = 0; i < strArray.Length; i++) 
            intArray[i] = int.Parse(strArray[i]);
        
        return intArray;
    

无论如何,希望这对某人有所帮助。

【讨论】:

失败不应该是沉默的,因此我不喜欢你的“安全”版本。在TryParse 本身之后对其进行建模,并将结果写入参数,并返回指示是否发生解析错误的值,在我看来,这将是我更好的选择。 (结果参数可以是out string[],但我建议让调用者提供一个List&lt;string&gt;,向其中添加可解析的列元素。或者,返回一个int?[],它保留有关的信息 列无法解析。 @Ben,我认为您的声明过于笼统。这取决于你想要什么。如果您已经知道您的价值观不同,并且只想要我发布的版本实现该目标的整数。如果您正在尝试验证输入并想知道是否有错误输入,那么我同意您的看法。在后一种情况下,我认为我不会做一个 bool 返回值。它为我提供了一些信息,但可能还不够。我会返回好条目的 int[] 并使用string[] Bad 的可选输出参数,这样您就可以向您的用户显示错误的值,而不是让他/她搜索字符串。【参考方案3】:

看看FileHelper 和CSV Reader 可能是值得的

希望他们能帮助你... 小心, 汤姆

【讨论】:

但问题是如何从表单字段中解析 CSV 字符串,而不是 CSV 文件 好的,从字符串输入创建一个文本流,根据 FileHelpers 实用程序,有一个方法 ReadString 它是 CommonEngine 类的一部分...见下面的原型...公共静态对象[] ReadString(Type recordClass, 字符串输入); 其实前几句就不要理会了..我再重复一遍,我的错!根据 FileHelpers util,有一个方法 ReadString,它是 CommonEngine 类的一部分...请参见下面的原型... public static object[] ReadString(Type recordClass, string input);【参考方案4】:

有一个很好的解析 CSV 文件的免费库:FileHelpers

    using FileHelpers;

    // First declare the record class

    [Delimitedrecord(";")]
    public class SampleType
    
        public string Field1;
        public int    Field2;
    


    public void ReadExample()
    
        FileHelperEngine engine = new FileHelperEngine(typeof(SampleType));

        SampleType[] records;    

        records = (SampleType[]) engine.ReadFile("source.txt");

        // Now "records" array contains all the records in the
        // sourcefile and can be acceded like this:

        int sum = records[0].Field2 + records[1].Field2;
    

【讨论】:

但问题是如何从表单字段中解析 CSV 字符串,而不是 CSV 文件【参考方案5】:
public bool ParseAndCheck(string source,
    out IList<int> goodItems, out IList<string> badItems)

    goodItems = new List<int>();
    badItems = new List<string>();

    foreach (string item in source.Split(','))
    
        int temp;
        if (int.TryParse(item, out temp))
            goodItems.Add(temp);
        else
            badItems.Add(item);
    

    return (badItems.Count < 1);

【讨论】:

【参考方案6】:

在 .NET 2.0 中你可以编写

string test = "123,14.5,125,151,1.55,477,777,888";

bool isParsingOk = true;


int[] results = Array.ConvertAll<string,int>(test.Split(','), 
    new Converter<string,int>(
        delegate(string num)
        
            int r;
            isParsingOk &= int.TryParse(num, out r);
            return r;
        ));

【讨论】:

【参考方案7】:

这很简单,我认为效果很好。它只返回有效数字:

static int[] SplitStringIntoInts(string list)
            
    int dummy;            
    return (from x in list.Split(',')
            where int.TryParse(x.ToString(), out dummy)
            select int.Parse(x.ToString())).ToArray();           

【讨论】:

抱歉,这行不通。 “from x in list”意味着每次迭代都将涉及字符串“list”中的单个字符。因此,如果我运行测试用例“10,20”,我将得到 int[]1,0,2,0 - 不是预期的结果。 @Kirk:这很容易通过将其更改为 from x in list.Split(',') 来解决。 @David:但是为什么要先调用ToList,然后再调用ToArray?只需 ToArray 自己就可以完成这项工作。 我对它做了一点修改(Split(','))。它比其他解决方案更小。为什么投反对票? :( 我不喜欢打电话给TryParse,然后重复打电话给Parse。我知道您这样做是为了压缩代码,但我认为总的来说这不是一个好主意。要么使用带有单个 TryParse 的语句 lambda,它可以正确捕获解析结果,或者只使用 Parse 并捕获异常(如果列表很大,并且通常不会保存不正确的值,则性能命中可以忽略不计,但代码会更简洁)。

以上是关于将 CSV 字符串解析为整数数组的主要内容,如果未能解决你的问题,请参考以下文章

将字符串数组转换为整数数组

csv转换obj

PHP CSV字符串到数组

Python csv字符串到数组

将 numpy 数组转换为 CSV 字符串,将 CSV 字符串转换回 numpy 数组

Logstash:将字符串转换为数组