我正在寻找关于如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且可能在值中有逗号,如公司名称。
我们正在考虑的一些想法是:带引号的标识符(value "," values ","等等)或使用|代替逗号。最大的问题是我们必须让它变得简单,否则客户就不会这么做。
我正在寻找关于如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且可能在值中有逗号,如公司名称。
我们正在考虑的一些想法是:带引号的标识符(value "," values ","等等)或使用|代替逗号。最大的问题是我们必须让它变得简单,否则客户就不会这么做。
当前回答
一个示例可能有助于说明如何在.csv文件中显示逗号。创建一个简单的文本文件,如下所示:
将此文本文件另存为后缀为“。csv”的文本文件,在Windows 10下使用Excel 2000打开。
aa、bb、cc, d, d "在电子表格演示中,下面的行应该看起来像上面的行,只是下面在d之间显示了一个逗号而不是分号。" aa,bb,cc,"d,d",即使在Excel中也适用
aa,bb,cc,"d,d",即使在Excel 2000中也是如此 aa,bb,cc,"d,d",即使在Excel 2000中也是如此 aa,bb,cc,"d, d",即使在Excel 2000中也是如此
aa,bb,cc, " d,d",这在Excel 2000中失败,因为在第一个引用之前有空格 aa,bb,cc, " d,d",这在Excel 2000中失败,因为在第一个引用之前有空格 aa,bb,cc, " d, d",这在Excel 2000中失败,因为在第一个引用之前有空格
aa,bb,cc,"d,d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。 aa,bb,cc,"d,d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。 aa,bb,cc,"d, d ",即使在Excel 2000中,即使在第2个引号前后有空格,这也是有效的。
规则:如果你想在csv文件的单元格(字段)中显示一个逗号: 用双引号开始和结束字段,但避免在第一个引号之前有空格
其他回答
添加对Microsoft的引用。VisualBasic(是的,它说的是VisualBasic,但它在c#中也一样好用——记住,最后它都是IL)。
使用Microsoft.VisualBasic.FileIO.TextFieldParser类来解析CSV文件。
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
您可以在字段周围加上双引号。我不喜欢这种方法,因为它增加了另一个特殊字符(双引号)。只需定义一个转义字符(通常是反斜杠),并在需要转义的地方使用它:
data,more data,more data\, even,yet more
您不必尝试匹配引号,而且需要解析的异常也更少。这也简化了您的代码。
您可以像这样读取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++;
}
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;
}
}
正如我在对harpo的回答的评论中提到的,他的解决方案在大多数情况下都很好,但是在某些情况下,当逗号直接相邻时,它无法在逗号上分割。
这是因为Regex字符串意外地表现为vertabim字符串。 为了获得正确的行为,regex字符串中的所有“字符都需要手动转义,而不使用vertabim转义。
Ie。正则表达式应该是这样的,使用手动转义:
",(?=(?:[^\"\"]*\"\"[^\"\"]*\"\")*(?![^\"\"]*\"\"))"
这转化为 ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"
当使用一个vertabim字符串 @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" 它表现为以下你可以看到如果你调试正则表达式:
",(?=(?:[^"]*"[^"]*")*(?![^"]*"))"
总之,我推荐harpo的解决方案,但要注意这个小陷阱!
我已经在CsvReader中包含了一些可选的故障保护,以便在发生此错误时通知您(如果您有预先知道的列数):
if (_expectedDataLength > 0 && values.Length != _expectedDataLength)
throw new DataLengthException(string.Format("Expected {0} columns when splitting csv, got {1}", _expectedDataLength, values.Length));
可以通过构造函数注入:
public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
_expectedDataLength = expectedDataLength;
}