1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-30 16:26:50 +00:00

Improve documentation and simplifies code for File::get_csv_line()

Also forbids using double quotes as a delimiter.

(cherry picked from commit b8c08ba5ad)
This commit is contained in:
Rémi Verschelde
2021-08-04 11:20:36 +02:00
parent 5497405cf7
commit b3c555504f
2 changed files with 28 additions and 20 deletions

View File

@@ -315,52 +315,53 @@ String FileAccess::get_line() const {
} }
Vector<String> FileAccess::get_csv_line(const String &p_delim) const { Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
ERR_FAIL_COND_V(p_delim.length() != 1, Vector<String>()); ERR_FAIL_COND_V_MSG(p_delim.length() != 1, Vector<String>(), "Only single character delimiters are supported to parse CSV lines.");
ERR_FAIL_COND_V_MSG(p_delim[0] == '"', Vector<String>(), "The double quotation mark character (\") is not supported as a delimiter for CSV lines.");
String l; String line;
// CSV can support entries with line breaks as long as they are enclosed
// in double quotes. So our "line" might be more than a single line in the
// text file.
int qc = 0; int qc = 0;
do { do {
if (eof_reached()) { if (eof_reached()) {
break; break;
} }
line += get_line() + "\n";
l += get_line() + "\n";
qc = 0; qc = 0;
for (int i = 0; i < l.length(); i++) { for (int i = 0; i < line.length(); i++) {
if (l[i] == '"') { if (line[i] == '"') {
qc++; qc++;
} }
} }
} while (qc % 2); } while (qc % 2);
l = l.substr(0, l.length() - 1); // Remove the extraneous newline we've added above.
line = line.substr(0, line.length() - 1);
Vector<String> strings; Vector<String> strings;
bool in_quote = false; bool in_quote = false;
String current; String current;
for (int i = 0; i < l.length(); i++) { for (int i = 0; i < line.length(); i++) {
CharType c = l[i]; CharType c = line[i];
CharType s[2] = { 0, 0 }; // A delimiter ends the current entry, unless it's in a quoted string.
if (!in_quote && c == p_delim[0]) { if (!in_quote && c == p_delim[0]) {
strings.push_back(current); strings.push_back(current);
current = String(); current = String();
} else if (c == '"') { } else if (c == '"') {
if (l[i + 1] == '"' && in_quote) { // Doubled quotes are escapes for intentional quotes in the string.
s[0] = '"'; if (line[i + 1] == '"' && in_quote) {
current += s; current += '"';
i++; i++;
} else { } else {
in_quote = !in_quote; in_quote = !in_quote;
} }
} else { } else {
s[0] = c; current += c;
current += s;
} }
} }
strings.push_back(current); strings.push_back(current);
return strings; return strings;

View File

@@ -99,8 +99,15 @@
<return type="PoolStringArray" /> <return type="PoolStringArray" />
<argument index="0" name="delim" type="String" default="&quot;,&quot;" /> <argument index="0" name="delim" type="String" default="&quot;,&quot;" />
<description> <description>
Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long. Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark.
Text is interpreted as being UTF-8 encoded. Text is interpreted as being UTF-8 encoded. Text values must be enclosed in double quotes if they include the delimiter character. Double quotes within a text value can be escaped by doubling their occurrence.
For example, the following CSV lines are valid and will be properly parsed as two strings each:
[codeblock]
Alice,"Hello, Bob!"
Bob,Alice! What a surprise!
Alice,"I thought you'd reply with ""Hello, world""."
[/codeblock]
Note how the second line can omit the enclosing quotes as it does not include the delimiter. However it [i]could[/i] very well use quotes, it was only written without for demonstration purposes. The third line must use [code]""[/code] for each quotation mark that needs to be interpreted as such instead of the end of a text value.
</description> </description>
</method> </method>
<method name="get_double" qualifiers="const"> <method name="get_double" qualifiers="const">