Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ability for custom delimiters #856

Merged
merged 1 commit into from Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
183 changes: 125 additions & 58 deletions src/main/java/org/json/CDL.java
Expand Up @@ -5,15 +5,15 @@
*/

/**
* 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>
Expand All @@ -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.
Expand All @@ -81,17 +79,25 @@ private static String getValue(JSONTokener x) throws JSONException {
* @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 != ' ') {
Expand All @@ -116,9 +122,17 @@ public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
* @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;
}

Expand All @@ -130,15 +144,23 @@ public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
* @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('"');
Expand Down Expand Up @@ -167,7 +189,15 @@ public static String rowToString(JSONArray ja) {
* @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);
}

/**
Expand All @@ -178,7 +208,15 @@ public static JSONArray toJSONArray(String string) throws JSONException {
* @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);
}

/**
Expand All @@ -189,9 +227,16 @@ public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
* @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);
}

/**
Expand All @@ -202,14 +247,21 @@ public static JSONArray toJSONArray(JSONArray names, String string)
* @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;
}
Expand All @@ -231,11 +283,19 @@ public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
* @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;
Expand All @@ -250,16 +310,23 @@ public static String toString(JSONArray ja) throws JSONException {
* @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;
}
StringBuilder sb = new StringBuilder();
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();
Expand Down