Skip to content
This repository was archived by the owner on Jan 6, 2021. It is now read-only.

Commit 9b65325

Browse files
committed
Added initial files
1 parent 407bb14 commit 9b65325

9 files changed

+384
-0
lines changed

src/classes/CSVReader.cls

+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/**
2+
* Created by zbrown on 7/8/2018.
3+
*/
4+
5+
public class CSVReader {
6+
// CONSTRUCTORS
7+
public CSVReader( String inCsvString )
8+
{
9+
this(inCsvString,false);
10+
}
11+
12+
public CSVReader( String inCsvString, Boolean inHasHeaders )
13+
{
14+
this.csvString = inCsvString;
15+
this.csvStringLength = inCsvString.length();
16+
this.hasHeaders = inHasHeaders;
17+
18+
parseToMap();
19+
}
20+
21+
22+
// PUBLIC PROPERTIES
23+
public Integer recordCount {
24+
get{
25+
Integer returnValue = csvArray.size();
26+
27+
if(hasHeaders && (returnValue > 0)){ returnValue = returnValue - 1; }
28+
29+
return returnValue;
30+
}
31+
}
32+
33+
public List<String> columnList { get; private set; }
34+
35+
public String find(String thisColumn,Integer thisRow){
36+
String returnValue;
37+
38+
returnValue = csvMap.get(thisColumn)[thisRow];
39+
return returnValue;
40+
}
41+
42+
public List<List<string>> csvArray { get; private set; }
43+
public Map<String,List<String>> csvMap { get; private set; }
44+
45+
46+
// BEGIN PRIVATE VARIABLES
47+
48+
private boolean EOF {
49+
get
50+
{
51+
if( this.position < this.csvStringLength )
52+
return false;
53+
else
54+
return true;
55+
}
56+
}
57+
58+
private String tokenString {
59+
get {
60+
if(!EOF){
61+
return this.csvString.mid(this.position,1);
62+
} else {
63+
return null;
64+
}
65+
}
66+
}
67+
68+
private String lookAheadString {
69+
get {
70+
if((this.position + 1) < this.csvStringLength){
71+
return this.csvString.mid(this.position+1,1);
72+
} else {
73+
return null;
74+
}
75+
}
76+
}
77+
78+
private integer columnWidth = 0;
79+
private boolean hasHeaders;
80+
private string csvString;
81+
private integer csvStringLength;
82+
private integer position = 0;
83+
84+
// STATIC CONSTANTS
85+
private static string COMMA = ',';
86+
private static string NL = '\n';
87+
private static string QUOTE = '"';
88+
private static string DOUBLE_QUOTE = '""';
89+
90+
91+
92+
93+
94+
/**
95+
* Reads up to a unquoted newline delimiter
96+
*
97+
* @return list of cell contents
98+
*/
99+
private List<String> parseLine(){
100+
List<String> returnValue = new List<String>();
101+
102+
do {
103+
104+
returnValue.add(parseCell());
105+
// throw away comma
106+
if( this.tokenString == COMMA){ this.position++; }
107+
} while((this.tokenString != null) && (this.tokenString != NL ));
108+
109+
this.position++;
110+
111+
if(returnValue.size() > columnWidth){ columnWidth = returnValue.size(); }
112+
113+
return returnValue;
114+
}
115+
116+
117+
/**
118+
* Reads up to an unquoted comma or newline
119+
*
120+
* @return string of cell contents
121+
*/
122+
private String parseCell(){
123+
String returnValue = '';
124+
Boolean isQuoteMode = false;
125+
Set<String> terminatorSet = new Set<String>();
126+
terminatorSet.add(COMMA);
127+
terminatorSet.add(NL);
128+
terminatorSet.add(null);
129+
130+
do {
131+
if(isQuoteMode){
132+
if((this.tokenString == QUOTE) && (this.lookAheadString == QUOTE)){
133+
returnValue = returnValue + QUOTE;
134+
this.position = this.position + 2; // Jump ahead two
135+
} else if(this.tokenString == QUOTE){
136+
this.position = this.position + 1; // Jump ahead one
137+
isQuoteMode = false;
138+
} else {
139+
returnValue = returnValue + this.tokenString;
140+
this.position = this.position + 1; // Jump ahead one
141+
}
142+
143+
} else {
144+
if(this.tokenString == QUOTE){
145+
this.position = this.position + 1; // Jump ahead one
146+
isQuoteMode = true;
147+
} else {
148+
returnValue = returnValue + this.tokenString;
149+
this.position = this.position + 1; // Jump ahead one
150+
}
151+
152+
}
153+
154+
} while(!terminatorSet.contains(this.tokenString) || (isQuoteMode == true));
155+
156+
157+
return returnValue;
158+
}
159+
160+
/**
161+
* Convers an integer to an excel column
162+
*
163+
* @param columnNumber
164+
*
165+
* @return An excel header string
166+
*/
167+
private String computeHeaderFromNumber(Integer columnNumber){
168+
String returnValue;
169+
String alphaList = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
170+
List<String> alphaArray = alphaList.split(',');
171+
172+
returnValue = alphaArray[math.mod(columnNumber,26)];
173+
174+
Integer pow = 1;
175+
while(columnNumber > Integer.valueOf(math.pow(26,pow))){
176+
returnValue = alphaArray[(columnNumber/Integer.valueOf(math.pow(26,pow)))] + returnValue;
177+
pow++;
178+
}
179+
180+
return returnValue;
181+
}
182+
183+
/**
184+
* Parses the raw data into an double array of strings
185+
*/
186+
private void parseToArray()
187+
{
188+
this.csvArray = new List<List<string>>();
189+
190+
191+
while(!EOF){
192+
this.csvArray.add(parseLine());
193+
}
194+
195+
}
196+
197+
/**
198+
* Converts the CSV array to a Map
199+
*/
200+
private void parseToMap()
201+
{
202+
this.csvMap = new Map<String,List<String>>();
203+
204+
parseToArray();
205+
this.columnList = new List<String>();
206+
Integer startIndex = 0;
207+
208+
209+
if(this.csvArray.size() > 0){
210+
if(this.hasHeaders){
211+
for(String mapKey : this.csvArray[0]){
212+
this.csvMap.put(mapKey,new List<String>());
213+
this.columnList.add(mapKey);
214+
}
215+
startIndex = 1;
216+
}
217+
else{
218+
for(Integer colnumber = 0; colnumber < this.csvArray[0].size(); colnumber++){
219+
String mapKey = computeHeaderFromNumber(colnumber);
220+
this.csvMap.put(mapKey,new List<String>());
221+
this.columnList.add(mapKey);
222+
}
223+
}
224+
if(this.csvArray.size() > startIndex + 1){
225+
for(Integer row = startIndex; row < this.csvArray.size() ; row++ ){
226+
List<String> thisRow = this.csvArray[row];
227+
228+
for(Integer index = 0; index < thisRow.size(); index++){
229+
if(index < columnList.size()){
230+
List<String> currentColumn = this.csvMap.get(this.columnList[index]);
231+
currentColumn.add(thisRow[index]);
232+
this.csvMap.put(this.columnList[index],currentColumn);
233+
}
234+
}
235+
236+
}
237+
}
238+
}
239+
}
240+
}

src/classes/CSVReader.cls-meta.xml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>42.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

src/classes/CSVReader_Test.cls

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Created by zbrown on 7/20/2018.
3+
*/
4+
5+
@isTest
6+
public class CSVReader_Test {
7+
8+
@testSetup
9+
public static void setUpTestData() {
10+
String str = 'Name,AccountNumber,Type,Accountsource,Industry\n Esha Patharabe,10001,Prospect,Test,Banking\n Trupti Nimje,10002,Prospect,Test,Banking';
11+
12+
}
13+
14+
15+
static testMethod void testCreateWithoutHeader(){
16+
String inputString = 'Id,Name,Description\nA0202033,Test 1,\"\"\" this is a quoted value\"\"\"\nA2023093,Test2,This is unquoted\nA3494494,Test 3,\"\"\" Single quote at the beginning\"\nA3334444,Test 4,\"This is unquoted\nThis has a new line\"\nA3334244,Test 5,\"This is unquoted,\nThis has a new line\"\nA3445566,Test 6,\"This, has a comma inside\"\n';
17+
18+
19+
CSVReader internalReader = new CSVReader(inputString);
20+
21+
}
22+
23+
static testMethod void testCreateWithHeader(){
24+
25+
String inputString = 'Name,AccountNumber,Type,Accountsource,Industry\n Esha Patharabe,10001,Prospect,Test,Banking\n Trupti Nimje,10002,Prospect,Test,Banking';
26+
CSVReader internalReader = new CSVReader(inputString,true);
27+
internalReader.find('Name',0);
28+
}
29+
30+
static testMethod void testTestController(){
31+
String inputString = 'Id,Name,Description\nA0202033,Test 1,\"\"\" this is a quoted value\"\"\"\nA2023093,Test2,This is unquoted\nA3494494,Test 3,\"\"\" Single quote at the beginning\"\nA3334444,Test 4,\"This is unquoted\nThis has a new line\"\nA3334244,Test 5,\"This is unquoted,\nThis has a new line\"\nA3445566,Test 6,\"This, has a comma inside\"\n';
32+
33+
34+
CSVTestController cont = new CSVTestController();
35+
CSVReader thisReader = cont.reader;
36+
37+
Integer idx = cont.getCSVLength();
38+
List<Integer> thisRI = cont.recordIndex;
39+
40+
41+
}
42+
43+
44+
}
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>42.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

src/classes/CSVTestController.cls

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Created by zb185019 on 7/18/2018.
3+
*/
4+
5+
public with sharing class CSVTestController {
6+
public CSVTestController(){
7+
8+
}
9+
10+
public CSVReader reader {
11+
get{
12+
if(internalReader == null){
13+
StaticResource srObject = [select id,body from StaticResource Where Name = 'Excel_Example_File'];
14+
String contents = srObject.body.toString();
15+
internalReader = new CSVReader(contents,false);
16+
return internalReader;
17+
18+
} else {
19+
return internalReader;
20+
}
21+
22+
}
23+
private set;
24+
}
25+
26+
public List<Integer> recordIndex {
27+
get{
28+
List<Integer> returnValue = new List<Integer>();
29+
for(Integer idx = 0; idx < internalReader.recordCount; idx++){
30+
returnValue.add(idx);
31+
}
32+
33+
return returnValue;
34+
}
35+
}
36+
private CSVReader internalReader;
37+
38+
public Integer getCSVLength() {
39+
40+
return reader.recordCount;
41+
42+
43+
}
44+
45+
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>42.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>

src/package.xml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<types>
4+
<members>CSVReader</members>
5+
<members>CSVReader_Test</members>
6+
<members>CSVTestController</members>
7+
<name>ApexClass</name>
8+
</types>
9+
<types>
10+
<members>CSVReaderTest</members>
11+
<name>ApexPage</name>
12+
</types>
13+
<version>40.0</version>
14+
</Package>

src/pages/CSVReaderTest.page

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!--
2+
- Created by zb185019 on 7/18/2018.
3+
-->
4+
5+
<apex:page id="CSVReaderTest" controller="CSVTestController">
6+
<table border="1" cellpadding="3" cellspacing="0">
7+
<tr>
8+
<apex:repeat value="{!reader.columnList}" var="col0"><td>{!col0}</td></apex:repeat>
9+
</tr>
10+
<apex:repeat value="{!reader.csvArray}" var="row">
11+
<tr>
12+
<apex:repeat value="{!row}" var="col"><td>{!col}</td></apex:repeat>
13+
</tr>
14+
</apex:repeat>
15+
</table>
16+
Test {!CSVLength}
17+
</apex:page>

src/pages/CSVReaderTest.page-meta.xml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexPage xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>42.0</apiVersion>
4+
<availableInTouch>false</availableInTouch>
5+
<confirmationTokenRequired>false</confirmationTokenRequired>
6+
<label>CSVReaderTest</label>
7+
</ApexPage>

0 commit comments

Comments
 (0)