問題: 匯出檔案.CSV時希望匯出逗號
已經搜尋過網路,說在要保留逗號,
的字串前後加雙引號"string"
可是怎麼加雙引號都沒用不知道是哪裡錯了QQ
看不出來哪裡有問題還請各位幫忙><謝謝
還請各位幫忙看一下是哪裡的問題
原始資料是有幾行的資料內容有逗號
while (!streamReader.EndOfStream)
{
string oneLine = streamReader.ReadLine(); // 一行
string streamWriter = "";
string address = "";
string[] oneLineArr = Regex.Split(oneLine, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); // 分割字串用逗號,但雙引號內的逗號不動
streamWriter = $"姓名:{oneLineArr[3]}電話: {oneLineArr[5]}地址:";
if (oneLine.Contains("\"")) // 如果有雙引號
{
Regex reg = new Regex("\"[^\"]*\""); // 取前後雙引號裡的字串
address = reg.Match(oneLine).Value.Replace("\"", ""); // 將原本資料中前後帶雙引號的取代掉
streamWriter += "\"" + address + "\"\r\n"; // 這個不行
streamWriter += String.Format("{0}{1}\"{2}\"", oneLineArr[7], oneLineArr[8], address); // 這個也不行
streamWriter += String.Format("{0}{1}{2}", oneLineArr[7], oneLineArr[8], address); // 這個也不行
streamWriter += String.Format("{0}", "\"" + address + "\""); // 這個也不行
}
else
{
streamWriter += oneLineArr[7] + oneLineArr[8] + oneLineArr[9];
}
newFileStreamWrite.WriteLine(streamWriter);
圖中有雙引號的都被欄位分割了!!可是就不要分割啊!!要保留逗號啊!!
這是notepad++開的檔案
網路上多半解法都是加 雙引號 "string" 可是還是抓不到
https://stackoverflow.com/questions/5740359/how-to-use-comma-in-csv-columns
已經用好久了還是不行.....
謝謝大神們
從你po出來的圖片看。你只是用""包起來。
但你並沒使用正確的格式。
如你
台北市"aaa.708 ,JJJ..."
但正確的格式是
台北市,"aaa.708 ,JJJ..."
或
"台北市aaa.708 ,JJJ..."
(因為我不懂你那個台北市是要當一欄還是放在一起。)
雙引號要包的是一整欄的資料。
如果你用第一種方式包的話。
你會害excel不懂這是什麼東東。就只能依照你的,分開了。
其實如果你的欄位中沒有數值型態的話,大可以將所有的欄位都用雙引號包起來。
也不需要再用正則處理了。
這樣改看看
string Pattern = "\"[^\"]*,[^\"]*\"";
Regex commaSpl = new Regex(Pattern, RegexOptions.Compiled);
List<string> outputCSV = new List<string>();
string FileToRead = @"s:\pi\test.csv";
using (StreamReader ReaderObject = new StreamReader(FileToRead))
{
string Line;
string oline = "";
string[] splitLine;
while ((Line = ReaderObject.ReadLine()) != null)
{
oline = "";
if (commaSpl.IsMatch(Line))
{
splitLine = Line.Split(new string[] { "\n" }, StringSplitOptions.None);
}
else
{
splitLine = Line.Split(new string[] { "," }, StringSplitOptions.None);
}
foreach (var s in splitLine)
oline += $"\"{s.Replace("\"", "")}\",";
outputCSV.Add(oline);
}
File.WriteAllText(@"s:\pi\new.csv", string.Join("\n", outputCSV));
}
糟,剛剛發現我沒有考慮到 "xxxxx,yyyy","zzzz" 的狀況
直接教他判斷是否數值。數值就不要包""
如果有包到"字串的話。我記得要用兩個"才行。用"好像不行。
.net我不會處理。所以沒辦法寫給他看。
只能告訴他理念。
只是不明白為何要每個欄位都要包""
現在用的截取程式段 內含參考來源
private static string[] SplitComma(string subjectString)
{
List result = new List();
// ref url: https://stackoverflow.com/questions/3268622/regex-to-split-line-csv-file
Regex rgx = new Regex(@"
# Parse CVS line. Capture next value in named group: 'val'
\s* # Ignore leading whitespace.
(?: # Group of value alternatives.
"" # Either a double quoted string,
(? # Capture contents between quotes.
[^""](""""[^""])* # Zero or more non-quotes, allowing
) # doubled "" quotes within string.
""\s* # Ignore whitespace following quote.
| (?[^,]*) # Or... zero or more non-commas.
) # End value alternatives group.
(?:,|$) # Match end is comma or EOS",
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
MatchCollection matches = rgx.Matches(subjectString);
foreach (Match mtch in matches)
{
if (mtch.Success && mtch.Index < subjectString.Length)
{
string value = mtch.Value.TrimEnd(',');
if (value.Length >= 2 && value.First() == '"' && value.Last() == '"')
value = value.Trim('"').Replace("""", """);
result.Add(value);
}
}
return result.ToArray();
}
因為""其實對csv來說,就是宣告字串格式的欄位。
認真來說,跟用陣列的用法很像。
用雙引號包起來的會視為一個欄位內容。
直接用雙引號包全部的欄位,就可以省下判斷字元處理。
(雖然內容中的雙引號還是需要處理就是了)
算是很懶的招。
像 chang137 po的,就是針對csv全部格式轉換的方式。
我只是教最簡單的處理。
但 chang137 是更完美的處理方式。
我幫忙將程式碼整理一下
private static string[] SplitComma(string subjectString)
{
List result = new List();
// ref url: https://stackoverflow.com/questions/3268622/regex-to-split-line-csv-file
Regex rgx = new Regex(@"
# Parse CVS line. Capture next value in named group: 'val'
\s* # Ignore leading whitespace.
(?: # Group of value alternatives.
"" # Either a double quoted string,
(? # Capture contents between quotes.
[^""](""""[^""])* # Zero or more non-quotes, allowing
) # doubled "" quotes within string.
""\s* # Ignore whitespace following quote.
| (?[^,]*) # Or... zero or more non-commas.
) # End value alternatives group.
(?:,|$) # Match end is comma or EOS",
RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
MatchCollection matches = rgx.Matches(subjectString);
foreach (Match mtch in matches)
{
if (mtch.Success && mtch.Index < subjectString.Length)
{
string value = mtch.Value.TrimEnd(',');
if (value.Length >= 2 && value.First() == '"' && value.Last() == '"')
value = value.Trim('"').Replace("""", """);
result.Add(value);
}
}
return result.ToArray();
}
是不是要將從 CSV 取得的欄位合併成一個呢?
如果是的話,雙引號要串在整個字串的開頭和結尾,例如:
小明,09xxxxxxxx,"abc,123"
轉成
"小明 09xxxxxxxx abc,123"
var result = "";
using (var streamReader = new StreamReader("test.csv"))
{
//切割欄位的正規式
var regex = new Regex("(?<=^|,)(\"(?:[^\"]|\"\")*\"|[^,]*)",
RegexOptions.Multiline);
//去除前後的雙引號
IEnumerable<string> clear(MatchCollection matches)
{
foreach(Match match in matches)
{
//去除頭尾空白
var value = match.Value.Trim();
//如果開頭是雙引號,就去除頭尾的雙引號
yield return value.StartsWith("\"") ?
match.Value.Substring(1, match.Value.Length - 2) : value;
}
};
while (!streamReader.EndOfStream)
{
var line = streamReader.ReadLine();
//切割欄位
var matches = regex.Matches(line);
//清理資料
var datas = clear(matches).ToList();
//合併各欄位
result += $"\"姓名: {datas[0]} 電話: {datas[1]} 地址: {datas[2]}\"\n";
}
File.WriteAllText(@"new.csv", result, Encoding.UTF8);
}
正規式部分參考 chang137 提供的連結:
https://stackoverflow.com/questions/3268622/regex-to-split-line-csv-file
小明,09xxxxxxxx,"abc,""123"
老王,09xxxxx123,台中市
"姓名: 小明 電話: 09xxxxxxxx 地址: abc,""123"
"姓名: 老王 電話: 09xxxxx123 地址: 台中市"
不過使用套件比較好啦,寫法也比較直覺。
Nuget 安裝 CsvHelper
public class Input
{
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
}
public class Output
{
public string Data { get; set; }
}
static void Main(string[] args)
{
var input = null as List<Input>;
//讀取資料
using (var reader = new StreamReader("test.csv", Encoding.UTF8))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = false;
input = csv.GetRecords<Input>().ToList();
}
//寫入資料
using (var writer = new StreamWriter("new2.csv", false, Encoding.UTF8))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = false;
var output = input.Select(it => new Output
{
Data = $"姓名: {it.Name} 電話: {it.Phone} 地址: {it.Address}"
});
csv.WriteRecords(output);
}
}
"姓名: 小明 電話: 09xxxxxxxx 地址: abc,""123"
姓名: 老王 電話: 09xxxxx123 地址: 台中市