Skip to content

Instantly share code, notes, and snippets.

@f1code
Created March 7, 2011 04:50
Show Gist options
  • Select an option

  • Save f1code/858086 to your computer and use it in GitHub Desktop.

Select an option

Save f1code/858086 to your computer and use it in GitHub Desktop.
SalesForce Apex CSV Parser
/**
* Used to read a delimited file.
*/
public class SSSCsvReader {
private String delim = ',';
// the input data
private String[] buffer;
public SSSCsvReader(String data){
this.buffer = data.split('\n');
}
public SSSCsvReader(String data, String delim){
this.buffer = data.split('\n');
this.delim = delim;
}
/**
* Read and parse next available line. Return null if end of stream.
*/
public String[] readLine(){
if(buffer.size() == 0)
return null;
String line = this.buffer.remove(0);
String[] parts = new String[] {};
while(line != ''){
Integer next = 0;
if(line.startsWith('"')){
line = line.substring(1); // strip initial
Integer quoteIndex = findQuote(line, 0);
while(quoteIndex == -1){
if(buffer.size() == 0){
// EOT!
quoteIndex = line.length();
} else {
// grab the next line
Integer skip = line.length();
line += '\n' + this.buffer.remove(0);
quoteIndex = findQuote(line, skip);
}
}
// advance to comma
next = quoteIndex + 1;
parts.add(line.substring(0, quoteIndex).replace('""', '"'));
} else {
next = line.indexOf(this.delim, next);
if(next == -1)
next = line.length();
// NB in Substring, "endindex" is the index of the character AFTER the last index to get
parts.add(line.substring(0, next));
}
if(next == line.length() - 1)
// case of a terminating comma.
parts.add('');
line = next < line.length() ? line.substring(next+1) : '';
}
if(parts.size() == 0)
// empty string - we still want to return something...
parts.add('');
return parts;
}
static private Pattern quotePattern = Pattern.compile('(?<!")"(?!")');
/**
* Find next quote in the line
*/
private Integer findQuote(String line, Integer skip){
Matcher m = quotePattern.matcher(line);
m.region(skip, m.regionEnd());
if(!m.find())
return -1;
return m.start();
}
}
@jsenich

jsenich commented Apr 13, 2016

Copy link
Copy Markdown

This is awesome! It works way better than the code sample for CSV parsing that is available on the Developer Force site. Thanks!

@aaronpfauth

Copy link
Copy Markdown

This is great - thanks for sharing!

@pventurino

Copy link
Copy Markdown

If you change the delimiter to '[\\r\\n]{1,2}' you will be able to also parse Excel exported files as are.

@abackhouse

Copy link
Copy Markdown

Thanks for this! Awesome.

@brbjr1

brbjr1 commented Jan 24, 2020

Copy link
Copy Markdown

Thank you for sharing.

@mohsinrazasfdc

Copy link
Copy Markdown

This works great. Thanks!

@vladiasynskyi

Copy link
Copy Markdown

The solution won't work if a cell (in CSV) has a value ending with a double quote.
In the following example, Cell 2 "Test" won't be recognised correctly
Cell 1;"Cell 2 ""Test""";Cell 3

@TrangOul

Copy link
Copy Markdown

Doesn't work properly. Multiline cells are not handled correctly. You cannot just use split. Also, correct line delimiter is CRLF (\r\n), not LF (\n).

@f1code

f1code commented Feb 19, 2025

Copy link
Copy Markdown
Author

I guess that's the idea here, to pull the next line in:

					Integer skip = line.length();
					line += '\n' + this.buffer.remove(0);

Code is almost 10 year old now but it did work properly at the time ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment