2016-01-20 119 views
-1

我得到了許多不同細節的.csv文件,最近還添加了大小和時代值。這導致導入工具出現問題,這是由於值在csv文件中將「*,*」替換爲「**」

(例如,

col1,col2,col3,col4,col5,col6 
abc,edf,"123,456,789","1,234","133,233,456",20/01/2016 
ogfsf,dcfdc,0,"1,456","134,567,456",11/01/2016 
jkglt,mnbc,0,0,"132,467,876",05/01/2016 

我想替換每行之間(「」)之間出現的不需要的(,)。我嘗試過使用sed,tr和其他類型的替換,但這並沒有幫助。我是否需要使用腳本來執行此操作,還是需要使用單個班輪替換命令?

Regards

+5

這對'sed'和'awk'來說當然是可行的。你嘗試了什麼?當然,最好的解決方案可能是教你的導入工具正確處理帶引號的字符串中的逗號。 – 5gon12eder

回答

1

隨着SED:

sed -E ':a;s/((,|^)"[^",]*),/\1/;ta' file 

細節:

:a # define the label "a" 
s/((,|^)"[^",]*),/\1/ # replace the first comma enclosed between quotes 
ta # if something is replaced, go to label "a" 

的-E(或-r)開關設置正則表達式語法ERE(擴展正則表達式),其允許|和避免轉義所有特殊字符,如括號。

(,|^)在這裏檢查報價是否真的是開盤報價。由於逗號從左到右依次被替換,所以當匹配時,可以確定下面的引號是開頭引號(因爲引號內的所有前面的逗號都已被替換)。

注意:這裏假設csv文件的引用部分不包含換行符。爲了處理帶有換行符的引用部分,它有點複雜,因爲您需要檢查引號的數量是否均勻,如果不是,則需要將下一行添加到模式空間,直到獲得偶數個引號:

sed -E ':a;/^([^"]|"[^"]*")*$/!{N;ba};:b;s/((,|^)"[^",]*),/\1/;tb' file 

爲了應對轉義引號:

sed -E ':a;/^([^"]|"[^"]*(""[^"]*)*")*$/!{N;ba};:b;s/((,|^)"[^",]*(""[^",]*)*),/\1/;tb;' file 
+0

謝謝你的回答! – Marcos

6

因爲你引用了逗號,所以你需要一個解析器。 regex可以做到這一點,但它很討厭,perl s Text::CSV解析得很好。

#!/usr/bin/env perl 

use strict; 
use warnings; 
use Text::CSV; 

my $csv = Text::CSV -> new ({ binary => 1, eol => "\n" }); 

while (my $row = $csv -> getline (\*DATA)) { 
    #remove commas in fields in the row 
    s|,||g for @$row; 
    #print the row. 
    $csv -> print (\*STDOUT, $row); 
} 

__DATA__ 
col1,col2,col3,col4,col5,col6 
abc,edf,"123,456,789","1,234","133,233,456",20/01/2016 
ogfsf,dcfdc,0,"1,456","134,567,456",11/01/2016 
jkglt,mnbc,0,0,"132,467,876",05/01/2016 

此打印:

col1,col2,col3,col4,col5,col6 
abc,edf,123456789,1234,133233456,20/01/2016 
ogfsf,dcfdc,0,1456,134567456,11/01/2016 
jkglt,mnbc,0,0,132467876,05/01/2016 

如所希望的。您可以使用\*STDIN從STDIN中讀取...。或者你可以使用open來做文件IO。

如果你想在一個腳本專門爲「一個班輪」這東西使用(這IMO是通常的理由要求一個正則表達式類型的解決方案):

perl -ne 'BEGIN{$csv = Text::CSV->new({eol=>"\n"})} $csv->print(\*STDOUT, [map {s|,||gr} do {$csv -> parse ($_); $csv ->fields()}])' filename 

這確實或多或少上面,和...好吧,這是一個折衷 - regex位很清楚,但map可能有點難以置信:)。

這是:通過線路(文件名或標準輸入)

  • 迭代線
  • 調用`解析
+3

Hooray,一個正確的答案! –

+1

我有一個新的討伐不正當使用'正則表達式'。我看到很多「我可以得到......的正則表達式」問題,雖然_technically_正則表達式可以做到,但最終得到的正則表達式最終會......糟糕的代碼的縮影,因爲它很難閱讀或理解。 (請參閱下面的一些答案,舉例說明我的意思 - 他們是_correct_,但很難遵循) – Sobrique

+1

我也是。正則表達式是一個很好的錘子,但不是每個問題都需要一把錘子。 XML,JSON,CSV等格式需要適合非脆弱解決方案的解析器。 –

0

通過Perl中,

$ perl -pe 's/,(?!(?:[^"]*"[^"]*")*[^"]*$)//g' file 
col1,col2,col3,col4,col5,col6 
abc,edf,"123456789","1234","133233456",20/01/2016 
ogfsf,dcfdc,0,"1456","134567456",11/01/2016 
jkglt,mnbc,0,0,"132467876",05/01/2016 

通過蟒。

>>> import re 
>>> with open('/home/gemini/Desktop/sample.txt') as f: 
     m = f.read() 
     print re.sub('"[^"]*"', lambda x: x.group().replace(',', ''), m) 


col1,col2,col3,col4,col5,col6 
abc,edf,"123456789","1234","133233456",20/01/2016 
ogfsf,dcfdc,0,"1456","134567456",11/01/2016 
jkglt,mnbc,0,0,"132467876",05/01/2016 
0

教你的進口商辦理報價:

B = [] 
for line in csv: 
    A = line.split('"')#A is now a list of strings in which every other element is within quotes 
    inquotes = False 
    for item in A: 
     if(inquotes): 
      B.append(item) 
     else: 
      C = item.split(',')#This is the regular csv stuff, the one we parse by commas 
      for element in C: 
       B.append(C) 
     inquotes = not(inquotes)#change state 

這是一種哈克,但將保留逗號代替鄰˚F刪除它們

0

這裏有一個紅寶石的一行,將盲目轉引自條目中刪除逗號:

ruby -rcsv -e 'CSV.foreach(ARGV.shift) {|row| puts CSV.generate_line row.map {|elem| elem.delete(",")}}' file.csv 
col1,col2,col3,col4,col5,col6 
abc,edf,123456789,1234,133233456,20/01/2016 
ogfsf,dcfdc,0,1456,134567456,11/01/2016 
jkglt,mnbc,0,0,132467876,05/01/2016 

如果你有一個像

"hello,world",foo,"1,234" 

你會想數據將逗號保留在字符串字段中。在這種情況下,

$ cat file.csv 
col1,col2,col3,col4,col5,col6 
abc,edf,"123,456,789","1,234","133,233,456",20/01/2016 
"a,b,c","d,e,f",0,0,0,0 

$ ruby -rcsv -e ' 
    CSV.foreach(ARGV.shift) do |row| 
     puts CSV.generate_line (
     row.map do |elem| 
      elem.match(/^\d+(,\d\d\d)+$/) ? elem.delete(",") : elem 
     end 
    ) 
    end 
    ' file.csv 
col1,col2,col3,col4,col5,col6 
abc,edf,123456789,1234,133233456,20/01/2016 
"a,b,c","d,e,f",0,0,0,0 
1

爲什麼不在第3,4,5列之前導出一個沒有的值?根據你所告訴導出文件正在通過添加不同類型的列來更改,必須告訴te進行第一次導出的人員,他們必須將其導出爲xxxxxxxxxx數字,而不是xxx,xxx,xxx數字。

它是在MS Excel或Ooo的jiffy中完成的,現在您正在創建一個代碼,當第一個用戶創建問題時,最終會出現更多問題。

把它放在白皮書中應該如何出口;文本文件,列等,它使程序員的生活變得更容易。

0

專用CSV解析器絕對可以做,雖然使用標準shell實用程序在這裏是一個簡單的GNU awk的解決方案:

awk -v FPAT='"[^"]*"|[^,]*' -v OFS=, '{for(i=1; i<=NF; i++) gsub(/,/, "", $i)} 1' file 
col1,col2,col3,col4,col5,col6 
abc,edf,"123456789","1234","133233456",20/01/2016 
ogfsf,dcfdc,0,"1456","134567456",11/01/2016 
jkglt,mnbc,0,0,"132467876",05/01/2016 

-v FPAT='"[^"]*"|[^,]*'休息每一行成爲"..."或非逗號字段的字段。

+0

上面的內容會刪除所有(,),而不是(())內的(,)。 – Marcos

+0

這不是事實,您可以看到附加的輸出,並且所有的逗號都在引號之外。 – anubhava