using System;
public class test
{
public static void Main()
{
using ( CsvReader reader = new CsvReader( "data.csv" ) )
{
foreach( string[] values in reader.RowEnumerator )
{
Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
}
}
Console.ReadLine();
}
}
这是课程 . 请注意,您也可以使用 Csv.Escape 函数写入有效的CSV .
using System.IO;
using System.Text.RegularExpressions;
public sealed class CsvReader : System.IDisposable
{
public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
{
}
public CsvReader( Stream stream )
{
__reader = new StreamReader( stream );
}
public System.Collections.IEnumerable RowEnumerator
{
get {
if ( null == __reader )
throw new System.ApplicationException( "I can't start reading without CSV input." );
__rowno = 0;
string sLine;
string sNextLine;
while ( null != ( sLine = __reader.ReadLine() ) )
{
while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
sLine += "\n" + sNextLine;
__rowno++;
string[] values = rexCsvSplitter.Split( sLine );
for ( int i = 0; i < values.Length; i++ )
values[i] = Csv.Unescape( values[i] );
yield return values;
}
__reader.Close();
}
}
public long RowIndex { get { return __rowno; } }
public void Dispose()
{
if ( null != __reader ) __reader.Dispose();
}
//============================================
private long __rowno = 0;
private TextReader __reader;
private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}
public static class Csv
{
public static string Escape( string s )
{
if ( s.Contains( QUOTE ) )
s = s.Replace( QUOTE, ESCAPED_QUOTE );
if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
s = QUOTE + s + QUOTE;
return s;
}
public static string Unescape( string s )
{
if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
{
s = s.Substring( 1, s.Length - 2 );
if ( s.Contains( ESCAPED_QUOTE ) )
s = s.Replace( ESCAPED_QUOTE, QUOTE );
}
return s;
}
private const string QUOTE = "\"";
private const string ESCAPED_QUOTE = "\"\"";
private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}
// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
string trimmedLine = line.Trim(new char[] { '\"' });
List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();
0
您可以像这样阅读csv文件 .
这利用了分裂和照顾空间 .
ArrayList List = new ArrayList();
static ServerSocket Server;
static Socket socket;
static ArrayList<Object> list = new ArrayList<Object>();
public static void ReadFromXcel() throws FileNotFoundException
{
File f = new File("Book.csv");
Scanner in = new Scanner(f);
int count =0;
String[] date;
String[] name;
String[] Temp = new String[10];
String[] Temp2 = new String[10];
String[] numbers;
ArrayList<String[]> List = new ArrayList<String[]>();
HashMap m = new HashMap();
in.nextLine();
date = in.nextLine().split(",");
name = in.nextLine().split(",");
numbers = in.nextLine().split(",");
while(in.hasNext())
{
String[] one = in.nextLine().split(",");
List.add(one);
}
int xount = 0;
//Making sure the lines don't start with a blank
for(int y = 0; y<= date.length-1; y++)
{
if(!date[y].equals(""))
{
Temp[xount] = date[y];
Temp2[xount] = name[y];
xount++;
}
}
date = Temp;
name =Temp2;
int counter = 0;
while(counter < List.size())
{
String[] list = List.get(counter);
String sNo = list[0];
String Surname = list[1];
String Name = list[2];
for(int x = 3; x < list.length; x++)
{
m.put(numbers[x], list[x]);
}
Object newOne = new newOne(sNo, Name, Surname, m, false);
StudentList.add(s);
System.out.println(s.sNo);
counter++;
}
2
public static IEnumerable<string> LineSplitter(this string line, char
separator, char skip = '"')
{
var fieldStart = 0;
for (var i = 0; i < line.Length; i++)
{
if (line[i] == separator)
{
yield return line.Substring(fieldStart, i - fieldStart);
fieldStart = i + 1;
}
else if (i == line.Length - 1)
{
yield return line.Substring(fieldStart, i - fieldStart + 1);
fieldStart = i + 1;
}
if (line[i] == '"')
for (i++; i < line.Length && line[i] != skip; i++) { }
}
if (line[line.Length - 1] == separator)
{
yield return string.Empty;
}
}
// Replace special CSV characters with single low-9 quotation mark
func Scrub(a interface{}) string {
s := fmt.Sprint(a)
s = strings.Replace(s, ",", "‚", -1)
s = strings.Replace(s, ";", "‚", -1)
return s
}
Dim parser As TextFieldParser = New TextFieldParser("C:\mar0112.csv")
parser.TextFieldType = FieldType.Delimited
parser.SetDelimiters(",")
While Not parser.EndOfData
'Processing row
Dim fields() As String = parser.ReadFields
For Each field As String In fields
'TODO: Process field
Next
parser.Close()
End While
([^,]*)(,.*) #first field, regex
"\1"\2 #first field, substitution
(.*,)([^,]*) #last field, regex
\1"\2" #last field, substitution
([^,]*,)(.*)(,.*,.*,.*) #second field (out of five fields)
([^,]*,[^,]*,)(.*)(,.*) #third field (out of four fields)
([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*) #fourth field (out of six fields)
23 回答
我通常对可以有任何逗号或任何特殊字符的字段进行URL编码 . 然后在任何视觉媒体中使用/显示时对其进行解码 .
(逗号变为%2C)
每种语言都应该有对URL进行URL编码和解码的方法 .
例如,在java中
我知道这是一个非常通用的解决方案,对于用户想要手动查看csv文件内容的情况,它可能不太理想 .
正如其他人所说,你需要转义包含引号的值 . 这是C♯中的一个小型CSV阅读器,支持引用值,包括嵌入式引号和回车 .
顺便说一句,这是经过单元测试的代码 . 我现在正在发布它,因为这个问题似乎出现了很多,其他人可能不需要整个库,只需简单的CSV支持即可 .
您可以按如下方式使用它:
这是课程 . 请注意,您也可以使用
Csv.Escape
函数写入有效的CSV .CSV格式使用逗号分隔值,包含回车符,换行符,逗号或双引号的值由双引号括起 . 引用包含双引号的值,并使用前一个引号对每个文字引号进行转义:例如,3个值:
将被编码为:
可以引用任何字段,但只能引用包含逗号,CR / NL或引号的字段 .
CSV格式没有真正的标准,但几乎所有应用程序都遵循here中记录的约定 . 其他地方提到的RFC不是CSV的标准,它是在MIME中使用CSV的RFC,包含一些非常规和不必要的限制,使其在MIME之外无用 .
我见过的许多CSV模块都不能容纳的事实是,在一个字段中可以编码多行,这意味着你不能假设每一行都是一个单独的记录,你要么不允许你的换行符数据或准备处理此事 .
在字符串周围加上双引号 . 这通常是what Excel does .
Ala Eli,
如果您想重新发明轮子,以下内容可能对您有用:
正如我在对harpo的回答中所提到的,他的解决方案很好并且在大多数情况下都适用,但是在某些情况下,当逗号彼此直接相邻时,它无法在逗号上分割 .
这是因为正则表达式字符串意外地表现为vertabim字符串 . 为了使这种行为正确,需要手动转义正则表达式字符串中的所有“字符而不使用vertabim转义符 .
IE浏览器 . 正则表达式应该使用手动转义:
",(?=(?:[^\"\"]*\"\"[^\"\"]*\"\")*(?![^\"\"]*\"\"))"
转化为
",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"
当使用vertabim字符串
@",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"
时,如果您调试正则表达式,它的行为如下所示:总而言之,我推荐harpo的解决方案,但请注意这个小问题!
我已经在CsvReader中包含了一些可选的故障保护,如果发生此错误(如果您有预先知道的列数),则通知您:
这可以通过构造函数注入:
我通常在我的CSV文件解析例程中执行此操作 . 假设'line'变量是CSV文件中的一行,并且所有列的值都用双引号括起来 . 执行以下两行后,您将在“values”集合中获得CSV列 .
您可以像这样阅读csv文件 .
这利用了分裂和照顾空间 .
对于2017年,csv已完全指定 - RFC 4180 .
这是一个非常常见的规范,并且被许多库完全覆盖(example) .
Simply use any easily-available csv library - 也就是说RFC 4180 .
实际上有CSV格式的规范以及如何处理逗号:
http://tools.ietf.org/html/rfc4180
因此,要获得值
foo
和bar,baz
,请执行以下操作:另一个需要考虑的重要要求(也来自规范):
由于这是关于一般做法,让我们从拇指规则开始:
不要使用CSV,请将XML与库一起使用来读取和写入xml文件 .
如果必须使用CSV . 正确执行并使用免费库来解析和存储CSV文件 .
至证明1),大多数CSV解析器不能识别编码,所以如果你不处理US-ASCII,你就会遇到麻烦 . 例如,excel 2002将CSV存储在本地编码中,而没有任何关于编码的注释 . CSV标准没有被广泛采用:( . 另一方面,xml标准很好用,它很好地处理编码 .
为了证明2),几乎所有语言都有大量的csv解析器,所以即使解决方案看起来非常简单,也不需要重新发明轮子 .
仅举几例:
for python使用csv模块构建
用于perl检查CPAN和Text::CSV
for php使用fgetcsv / fputcsv函数构建
for java check SuperCVS library
实际上,如果您不打算在嵌入式设备上解析它,则无需手动实现 .
首先,让我们问自己,“为什么我们觉得需要以不同的方式处理逗号的CSV文件?”
对我来说,答案是,“因为当我将数据导出到CSV文件中时,字段中的逗号消失,我的字段被分成多个字段,其中逗号出现在原始数据中 . ” (这是因为逗号是CSV字段分隔符 . )
根据您的情况,半冒号也可以用作CSV字段分隔符 .
根据我的要求,我可以使用一个字符,例如单个低9引号,看起来像逗号 .
那么,这是你如何在Go中做到的:
替换函数中的第二个逗号字符是十进制8218 .
请注意,如果您的客户端可能只有ascii文本阅读器,则此decima 8218字符将不会像逗号一样 . 如果这是你的情况,那么我建议使用逗号(或分号)围绕字段,每个RFC 4128使用双引号:https://tools.ietf.org/html/rfc4180
添加对Microsoft.VisualBasic的引用(是的,它说VisualBasic但它也适用于C# - 请记住,最后它只是IL) .
使用
Microsoft.VisualBasic.FileIO.TextFieldParser
类来解析CSV文件以下是示例代码:我认为解决这个问题的最简单方法是让客户在excel中打开csv,然后按ctrl r将所有逗号替换为你想要的任何标识符 . 这对于客户来说非常简单,只需要对代码进行一次更改即可阅读您选择的分隔符 .
您可以使用替代的“分隔符”,如“;”或“|”但最简单的可能只是引用大多数(体面的)CSV库和大多数不错的电子表格所支持的引用 .
对于more on CSV delimiters and a spec for a standard format for describing delimiters and quoting see this webpage
我发现的最简单的解决方案是LibreOffice使用的解决方案:
将所有文字
"
替换为”
在字符串周围加上双引号
您还可以使用Excel使用的那个:
将所有文字
"
替换为""
在字符串周围加上双引号
请注意其他人建议仅执行上面的步骤2,但这不适用于
"
后跟,
的行,就像在CSV中您希望单个列包含字符串hello",world
,因为CSV会读取:这被解释为具有两列的行:
hello
和world"
你可以在字段周围加上双引号 . 我不喜欢这种方法,因为它增加了另一个特殊字符(双引号) . 只需定义一个转义字符(通常是反斜杠)并在任何需要转义的地方使用它:
您不必尝试匹配引号,并且您解析的异常更少 . 这也简化了您的代码 .
有一个库可以通过nuget处理几乎任何格式良好的CSV(.net) - CsvHelper
Example to map to a class:
Example to read individual fields:
Letting the client drive the file format:
,
是标准字段分隔符,"
是用于转义包含分隔符,引号或行结尾的字段的标准值 .要使用(例如)
#
表示字段,使用'
表示转义:More Documentation
在欧洲,我们有这个问题必须早于这个问题 . 在欧洲,我们使用逗号作为小数点 . 请看下面这个数字:
因此无法对CSV文件使用逗号分隔符 . 由于这个原因,欧洲的CSV文件用分号(
;
)分隔 .像Microsoft Excel这样的程序可以用分号读取文件,并且可以从分隔符切换 . 您甚至可以使用选项卡(
\t
)作为分隔符 . 见this answer from Supper User .我使用了Csvreader库但是通过使用它我通过在列值中从逗号(,)爆炸获得数据 .
因此,如果要在大多数列值中插入包含逗号(,)的CSV文件数据,可以使用以下函数 . 作者链接=> https://gist.github.com/jaywilliams/385876
使用制表符(\ t)分隔字段 .
如果您对如何解析文件的更多教育练习感兴趣(使用CSV作为示例),您可以查看Julian Bucknall的this article . 我喜欢这篇文章,因为它将问题分解为更小的问题这是不太难以克服的 . 首先创建一个语法,一旦你有一个好的语法,将语法转换为代码是一个相对简单和有条理的过程 .
本文使用C#并在底部有一个链接来下载代码 .
如果您使用 *nix-system ,可以访问 sed 并且可以有一个或多个 unwanted commas only in a specific field 的CSV,您可以使用以下单行,以便将它们包含在
"
中,因为RFC4180 Section 2建议:根据不需要的逗号所在的字段,您必须更改/扩展正则表达式的捕获组(以及替换) .
上面的示例将第四个字段(六个中)括在引号中 .
与--in-place-option结合使用,您可以将这些更改直接应用于文件 .
为了“构建”正确的正则表达式,有一个简单的原则可以遵循:
对于CSV中包含不需要的逗号的字段之前的每个字段,您都要编写一个
[^,]*,
并将它们全部放在一个捕获组中 .对于包含不需要的逗号的字段,您可以编写
(.*)
.对于包含不需要的逗号的字段后面的每个字段,您编写一个
,.*
并将它们全部放在一个捕获组中 .以下是根据具体字段对不同可能的正则表达式/替换进行的简短概述 . 如果没有给出,替换是
\1"\2"\3
.如果要删除带有
sed
的不需要的逗号而不是用引号括起它们,请参阅this answer .