mirror of
https://github.com/stleary/JSON-java.git
synced 2025-08-02 11:05:28 -04:00
Merge pull request #856 from michael-ameri/custom-delimiter
add ability for custom delimiters
This commit is contained in:
commit
8550175556
@ -5,15 +5,15 @@ Public Domain.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This provides static methods to convert comma delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma delimited text. Comma
|
||||
* This provides static methods to convert comma (or otherwise) delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma (or otherwise) delimited text. Comma
|
||||
* delimited text is a very popular format for data interchange. It is
|
||||
* understood by most database, spreadsheet, and organizer programs.
|
||||
* <p>
|
||||
* Each row of text represents a row in a table or a data record. Each row
|
||||
* ends with a NEWLINE character. Each row contains one or more values.
|
||||
* Values are separated by commas. A value can contain any character except
|
||||
* for comma, unless is is wrapped in single quotes or double quotes.
|
||||
* for comma, unless it is wrapped in single quotes or double quotes.
|
||||
* <p>
|
||||
* The first row usually contains the names of the columns.
|
||||
* <p>
|
||||
@ -29,50 +29,48 @@ public class CDL {
|
||||
* Get the next value. The value can be wrapped in quotes. The value can
|
||||
* be empty.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @param delimiter used in the file
|
||||
* @return The value string, or null if empty.
|
||||
* @throws JSONException if the quoted string is badly formed.
|
||||
*/
|
||||
private static String getValue(JSONTokener x) throws JSONException {
|
||||
private static String getValue(JSONTokener x, char delimiter) throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = x.next();
|
||||
} while (c == ' ' || c == '\t');
|
||||
switch (c) {
|
||||
case 0:
|
||||
return null;
|
||||
case '"':
|
||||
case '\'':
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = x.next();
|
||||
if (c == q) {
|
||||
//Handle escaped double-quote
|
||||
char nextC = x.next();
|
||||
if(nextC != '\"') {
|
||||
// if our quote was the end of the file, don't step
|
||||
if(nextC > 0) {
|
||||
x.back();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 || c == '\n' || c == '\r') {
|
||||
throw x.syntaxError("Missing close quote '" + q + "'.");
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
case ',':
|
||||
x.back();
|
||||
return "";
|
||||
default:
|
||||
x.back();
|
||||
return x.nextTo(',');
|
||||
}
|
||||
}
|
||||
if (c == 0) {
|
||||
return null;
|
||||
} else if (c == '"' || c == '\'') {
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
c = x.next();
|
||||
if (c == q) {
|
||||
//Handle escaped double-quote
|
||||
char nextC = x.next();
|
||||
if (nextC != '\"') {
|
||||
// if our quote was the end of the file, don't step
|
||||
if (nextC > 0) {
|
||||
x.back();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 || c == '\n' || c == '\r') {
|
||||
throw x.syntaxError("Missing close quote '" + q + "'.");
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
} else if (c == delimiter) {
|
||||
x.back();
|
||||
return "";
|
||||
}
|
||||
x.back();
|
||||
return x.nextTo(delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of strings from a row of comma delimited values.
|
||||
@ -81,17 +79,25 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
|
||||
return rowToJSONArray(x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #rowToJSONArray(JSONTokener)}, but with a custom delimiter.
|
||||
* @see #rowToJSONArray(JSONTokener)
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x, char delimiter) throws JSONException {
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
String value = getValue(x);
|
||||
String value = getValue(x,delimiter);
|
||||
char c = x.next();
|
||||
if (value == null ||
|
||||
(ja.length() == 0 && value.length() == 0 && c != ',')) {
|
||||
(ja.length() == 0 && value.length() == 0 && c != delimiter)) {
|
||||
return null;
|
||||
}
|
||||
ja.put(value);
|
||||
for (;;) {
|
||||
if (c == ',') {
|
||||
if (c == delimiter) {
|
||||
break;
|
||||
}
|
||||
if (c != ' ') {
|
||||
@ -116,9 +122,17 @@ public class CDL {
|
||||
* @return A JSONObject combining the names and values.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x);
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) throws JSONException {
|
||||
return rowToJSONObject(names, x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #rowToJSONObject(JSONArray, JSONTokener)}, but with a custom {@code delimiter}.
|
||||
*
|
||||
* @see #rowToJSONObject(JSONArray, JSONTokener)
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x, char delimiter) throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x, delimiter);
|
||||
return ja != null ? ja.toJSONObject(names) : null;
|
||||
}
|
||||
|
||||
@ -130,15 +144,23 @@ public class CDL {
|
||||
* @return A string ending in NEWLINE.
|
||||
*/
|
||||
public static String rowToString(JSONArray ja) {
|
||||
return rowToString(ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #rowToString(JSONArray)}, but with a custom delimiter.
|
||||
* @see #rowToString(JSONArray)
|
||||
*/
|
||||
public static String rowToString(JSONArray ja, char delimiter) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
sb.append(delimiter);
|
||||
}
|
||||
Object object = ja.opt(i);
|
||||
if (object != null) {
|
||||
String string = object.toString();
|
||||
if (string.length() > 0 && (string.indexOf(',') >= 0 ||
|
||||
if (string.length() > 0 && (string.indexOf(delimiter) >= 0 ||
|
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
|
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
|
||||
sb.append('"');
|
||||
@ -167,7 +189,15 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string));
|
||||
return toJSONArray(string, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toJSONArray(String)}, but with a custom delimiter.
|
||||
* @see #toJSONArray(String)
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string, char delimiter) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string), delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +208,15 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x), x);
|
||||
return toJSONArray(x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toJSONArray(JSONTokener)}, but with a custom delimiter.
|
||||
* @see #toJSONArray(JSONTokener)
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x, char delimiter) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x, delimiter), x, delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,9 +227,16 @@ public class CDL {
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string)
|
||||
throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string));
|
||||
public static JSONArray toJSONArray(JSONArray names, String string) throws JSONException {
|
||||
return toJSONArray(names, string, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toJSONArray(JSONArray, String)}, but with a custom delimiter.
|
||||
* @see #toJSONArray(JSONArray, String)
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string, char delimiter) throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string), delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,14 +247,21 @@ public class CDL {
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x) throws JSONException {
|
||||
return toJSONArray(names, x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toJSONArray(JSONArray, JSONTokener)}, but with a custom delimiter.
|
||||
* @see #toJSONArray(JSONArray, JSONTokener)
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x, char delimiter) throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
JSONObject jo = rowToJSONObject(names, x);
|
||||
JSONObject jo = rowToJSONObject(names, x, delimiter);
|
||||
if (jo == null) {
|
||||
break;
|
||||
}
|
||||
@ -231,11 +283,19 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
return toString(ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toString(JSONArray)}, but with a custom delimiter.
|
||||
* @see #toString(JSONArray)
|
||||
*/
|
||||
public static String toString(JSONArray ja, char delimiter) throws JSONException {
|
||||
JSONObject jo = ja.optJSONObject(0);
|
||||
if (jo != null) {
|
||||
JSONArray names = jo.names();
|
||||
if (names != null) {
|
||||
return rowToString(names) + toString(names, ja);
|
||||
return rowToString(names, delimiter) + toString(names, ja, delimiter);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -250,8 +310,15 @@ public class CDL {
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja)
|
||||
throws JSONException {
|
||||
public static String toString(JSONArray names, JSONArray ja) throws JSONException {
|
||||
return toString(names, ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #toString(JSONArray,JSONArray)}, but with a custom delimiter.
|
||||
* @see #toString(JSONArray,JSONArray)
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja, char delimiter) throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
@ -259,7 +326,7 @@ public class CDL {
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
JSONObject jo = ja.optJSONObject(i);
|
||||
if (jo != null) {
|
||||
sb.append(rowToString(jo.toJSONArray(names)));
|
||||
sb.append(rowToString(jo.toJSONArray(names), delimiter));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
@ -24,14 +24,13 @@ public class CDLTest {
|
||||
* String of lines where the column names are in the first row,
|
||||
* and all subsequent rows are values. All keys and values should be legal.
|
||||
*/
|
||||
String lines = new String(
|
||||
"Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" +
|
||||
"val1, val2, val3, val4, val5, val6, val7\n" +
|
||||
"1, 2, 3, 4\t, 5, 6, 7\n" +
|
||||
"true, false, true, true, false, false, false\n" +
|
||||
"0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" +
|
||||
"\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", va\'l6, val7\n"
|
||||
);
|
||||
private static final String LINES = "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" +
|
||||
"val1, val2, val3, val4, val5, val6, val7\n" +
|
||||
"1, 2, 3, 4\t, 5, 6, 7\n" +
|
||||
"true, false, true, true, false, false, false\n" +
|
||||
"0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" +
|
||||
"\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", va'l6, val7\n";
|
||||
|
||||
|
||||
/**
|
||||
* CDL.toJSONArray() adds all values as strings, with no filtering or
|
||||
@ -39,12 +38,11 @@ public class CDLTest {
|
||||
* values all must be quoted in the cases where the JSONObject parsing
|
||||
* might normally convert the value into a non-string.
|
||||
*/
|
||||
String expectedLines = new String(
|
||||
"[{Col 1:val1, Col 2:val2, Col 3:val3, Col 4:val4, Col 5:val5, Col 6:val6, Col 7:val7}, "+
|
||||
"{Col 1:\"1\", Col 2:\"2\", Col 3:\"3\", Col 4:\"4\", Col 5:\"5\", Col 6:\"6\", Col 7:\"7\"}, "+
|
||||
"{Col 1:\"true\", Col 2:\"false\", Col 3:\"true\", Col 4:\"true\", Col 5:\"false\", Col 6:\"false\", Col 7:\"false\"}, "+
|
||||
"{Col 1:\"0.23\", Col 2:\"57.42\", Col 3:\"5e27\", Col 4:\"-234.879\", Col 5:\"2.34e5\", Col 6:\"0.0\", Col 7:\"9e-3\"}, "+
|
||||
"{Col 1:\"va\tl1\", Col 2:\"v\bal2\", Col 3:val3, Col 4:\"val\f4\", Col 5:val5, Col 6:va\'l6, Col 7:val7}]");
|
||||
private static final String EXPECTED_LINES = "[{Col 1:val1, Col 2:val2, Col 3:val3, Col 4:val4, Col 5:val5, Col 6:val6, Col 7:val7}, " +
|
||||
"{Col 1:\"1\", Col 2:\"2\", Col 3:\"3\", Col 4:\"4\", Col 5:\"5\", Col 6:\"6\", Col 7:\"7\"}, " +
|
||||
"{Col 1:\"true\", Col 2:\"false\", Col 3:\"true\", Col 4:\"true\", Col 5:\"false\", Col 6:\"false\", Col 7:\"false\"}, " +
|
||||
"{Col 1:\"0.23\", Col 2:\"57.42\", Col 3:\"5e27\", Col 4:\"-234.879\", Col 5:\"2.34e5\", Col 6:\"0.0\", Col 7:\"9e-3\"}, " +
|
||||
"{Col 1:\"va\tl1\", Col 2:\"v\bal2\", Col 3:val3, Col 4:\"val\f4\", Col 5:val5, Col 6:va'l6, Col 7:val7}]";
|
||||
|
||||
/**
|
||||
* Attempts to create a JSONArray from a null string.
|
||||
@ -194,8 +192,7 @@ public class CDLTest {
|
||||
public void emptyString() {
|
||||
String emptyStr = "";
|
||||
JSONArray jsonArray = CDL.toJSONArray(emptyStr);
|
||||
assertTrue("CDL should return null when the input string is empty",
|
||||
jsonArray == null);
|
||||
assertNull("CDL should return null when the input string is empty", jsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,7 +251,7 @@ public class CDLTest {
|
||||
jsonObject.put("Col \r1", "V1");
|
||||
// \r will be filtered from value
|
||||
jsonObject.put("Col 2", "V2\r");
|
||||
assertTrue("expected length should be 1",jsonArray.length() == 1);
|
||||
assertEquals("expected length should be 1", 1, jsonArray.length());
|
||||
String cdlStr = CDL.toString(jsonArray);
|
||||
jsonObject = jsonArray.getJSONObject(0);
|
||||
assertTrue(cdlStr.contains("\"Col 1\""));
|
||||
@ -268,8 +265,15 @@ public class CDLTest {
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArray() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(this.lines);
|
||||
JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
||||
}
|
||||
@Test
|
||||
public void textToJSONArrayPipeDelimited() {
|
||||
char delimiter = '|';
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES.replaceAll(",", String.valueOf(delimiter)), delimiter);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
@ -293,10 +297,24 @@ public class CDLTest {
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArrayAndBackToString() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(this.lines);
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES);
|
||||
String jsonStr = CDL.toString(jsonArray);
|
||||
JSONArray finalJsonArray = CDL.toJSONArray(jsonStr);
|
||||
JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSONArray from a string of lines,
|
||||
* then convert to string and then back to JSONArray
|
||||
* with a custom delimiter
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArrayAndBackToStringCustomDelimiter() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES, ',');
|
||||
String jsonStr = CDL.toString(jsonArray, ';');
|
||||
JSONArray finalJsonArray = CDL.toJSONArray(jsonStr, ';');
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user