| Bytes | Lang | Time | Link |
|---|---|---|---|
| 033 | Dyalog APL | 250821T060655Z | Aaron |
| 031 | AWK | 250820T152131Z | xrs |
| 032 | Vim | 160928T161202Z | Christia |
| 081 | PHP | 160926T123018Z | Titus |
| 059 | R | 160926T115956Z | rturnbul |
| 056 | Haskell | 160926T114759Z | BlackCap |
| nan | Sh + GNU Sed | 160925T152203Z | someonew |
| 080 | Ruby | 160925T144233Z | lynn |
| 027 | 05AB1E | 160925T145908Z | Emigna |
| 090 | JavaScript ES6 | 160924T222314Z | Arnauld |
| 092 | Python 2 | 160924T215658Z | Copper |
| 129 | NodeJS | 160924T225605Z | DanTheMa |
Dyalog APL, ⎕IO←0, 33 chars
Takes which field to remove commas from on the left (0-indexed) and vector of lines on the right.
{⍵/⍨~((','=⍵)∧(1+⍺×2)=⊢)+\'"'=⍵}¨
'"'=⍵ # Find the quote marks
+\ # Plus scan. This will mark each quote-delimited section
# e.g. "hello","there" becomes
# 111111223333334
( ) # Apply this little train
(1+⍺×2)=⊢ # Find where the input equals 2⍺+1
# This is then the left argument selecting every other quote-delimited section
∧ # and
(','=⍵) # where the original input was a comma
( ) # This is then the intersection of which field to edit and where the comma is
~ # Logical not
/⍨ # Replicate (filter)
⍵ # original input
{ }¨ # Run on each input line
💎
Created with the help of Luminespire.
AWK, 31 bytes
{gsub(/,/,X)}gsub(/""/,"\",\"")
I think gensub looks more elegant:
$0=gensub(/([^"]),([^"])/,"\\1\\2","g")
Vim, 32 keystrokes (excluding column index)
This uses 1-based column indices (which might make this answer invalid).
The problem here is that Vim does not start from the current character but rather from the following one... So it's not "easy" to match the 1st set of quotes. Instead, it finds the closing quotes and selects backwards.
Solution
qq + the column index + /\v"(,"|$)<cr>vF":s/\%V,//<cr><cr>@qq@q
Explanation
qqstarts recording macroq/\v"(,"|$)<cr>searches for the next ending quote or end if line. Preceded by the input column number, it finds the nth occurrencevF"visually selects the previous quote":s/\%V,//<cr>substitutes in the visual selection (\%V) every comma by nothing<cr>goes to the next line@qq@qmakes the macro recursive, stops it and then play it until the end of the file.
Gotchas
- If a column only contains commas, it will be detected as a column end and will break. This is a gray zone, I will adapt the answer is the question adds this to the test cases.
PHP, 81 bytes
while($r=fgetcsv(STDIN)){$r[$n=argv[1]]=strtr($r[$n],",","");fputcsv(STDOUT,$r);}
Run with php -r '<code>' <n> < <csvsource> > <csvtarget>.
R, 59 bytes
function(f,n){x=read.csv(f,h=0);x[,n]=gsub(",","",x[,n]);x}
A simple function that takes f, the location of the csv file, and n, the column number to replace. Reads in the file, removes all commas from the nth column, returns the resulting data frame. R indexes from 1, not from 0.
Haskell, 56 bytes
n!x=Math.FFT.Base.adjust(filter(/=','))n.read$'[':x++"]"
Without adjust you'd have to do something crazy like this:
n#(a,b)|a==n|filter(/=',')b|1<2=b; .. (n#)=<<zip ..
Sh + GNU Sed GNU Sed, 36 28 + 1 bytes
Run with -r flag.
sed -r 's/(,?"\w*),?(\w*")/\1\2/'$1
One argument to select proper column (1-indexed). This uses a GNU-specific sed extension.
Old version: s/(,?\"\w*),?(\w*\")/\1\2/3
This required replacing the last 3 to select the proper column (1-indexed), which I'm not sure is allowed.
Ruby, 80 bytes
require'csv'
->n,x{CSV.read(x).map{|a|a[n].delete!',';a.to_csv(force_quotes:1)}}
A lambda that takes n and a file path argument, and returns a list of CSV rows.
05AB1E, 27 bytes
U|vy“","“©¡vyNXQi","-}})®ý,
Explanation
U # store index in X
|v # for each line
y“","“©¡ # split on ","
v } # for each in the split list
yNXQi","-} # if it's index equals X, remove any commas
) # wrap in list
®ý, # merge on "," and print
JavaScript (ES6), 95 93 90 bytes
Takes the content of the CSV file as its first parameter and the column index as its second parameter, with currying syntax.
let f =
s=>n=>s.split(/("[^"]*")/).map(c=>(c<' '?(k=0,c):k++-n*2?c:c.split`,`.join``),k=-1).join``
console.log(f(
`"apple","banana","apple,banana","orange"
"grape","orange","grape,orange","sprout"
`)(2));
Python 2, 129 126 125 98 96 94 92 bytes
lambda n,f:''.join(c*((r[:i].count('"')-n*2)*','!=c)for r in open(f)for i,c in enumerate(r))
This is a lambda expression; to use it, prefix lambda with s=.
Iterates through each character of each line, filtering characters based on whether it's a comma and it's in a double-quoted string.
Now doesn't use the csv module at all!
Example run:
>>> s=lambda n,f:''.join(c*((r[:i].count('"')-n*2)*','!=c)for r in open(f)for i,c in enumerate(r))
>>> print s(2, 'test.csv')
"apple","banana","applebanana","orange"
"grape","orange","grapeorange","sprout"
NodeJS, 129 bytes
(f,n)=>(require("fs").readFileSync(f)+"").split`
`.map(a=>a.match(/".*?"/g).map((b,i)=>i-n?b:b.replace(/,/g,"")).join`,`).join`
`
Defines an anonymous function that takes a file path and a number as input. It is no longer required to take input as a file, but I will leave this here for comparison.