@@ -1061,42 +1061,40 @@ between lines.
1061
1061
```
1062
1062
function parseINI(string) {
1063
1063
// Start with an object to hold the top-level fields
1064
- return string.split(/\r?\n/).reduce((sections, line) => {
1065
- if (/^\s*(;.*)?$/.test(line)) return sections ;
1066
-
1064
+ let result = {};
1065
+ let section = result ;
1066
+ string.split(/\r?\n/).forEach(line => {
1067
1067
let match;
1068
- if (match = line.match(/^\[(.*)\]$/)) {
1069
- return [...sections, {title: match[1], fields: []}];
1070
- } else if (match = line.match(/^(\w+)=(.*)$/)) {
1071
- let [_, name, value] = match;
1072
- let {title, fields} = sections[sections.length - 1];
1073
- return [...sections.slice(1),
1074
- {title, fields: [{name, value}, ...fields]}];
1075
- } else {
1076
- throw new Error("Line '" + line + "' is invalid.");
1068
+ if (match = line.match(/^(\w+)=(.*)$/)) {
1069
+ section[match[1]] = match[2];
1070
+ } else if (match = line.match(/^\[(.*)\]$/)) {
1071
+ section = result[match[1]] = {};
1072
+ } else if (!/^\s*(;.*)?$/.test(line)) {
1073
+ throw new Error("Line '" + line + "' is not valid.");
1077
1074
}
1078
- }, [{title: null, fields: []}]);
1075
+ });
1076
+ return result;
1079
1077
}
1078
+
1079
+ console.log(parseINI(`
1080
+ name=Vasilis
1081
+ [address]
1082
+ city=Tessaloniki`));
1083
+ // → {name: "Vasilis", address: {city: "Tessaloniki"}}
1080
1084
```
1081
1085
1082
1086
{{index "parseINI function", parsing}}
1083
1087
1088
+ The code goes over the file's lines and builds up an object.
1089
+ Properties at the top are stored directly into the object, whereas
1090
+ properties found in sections are stored in sub-objects stored under
1091
+ the section's name. The ` section ` binding points at the object that
1092
+ holds the current section.
1084
1093
1085
- The code reduces the file's lines to an array of sections, starting
1086
- with a single, untitled section.
1087
-
1088
- When it finds an empty line or a comment, it ignores it. The
1089
- expression ` /^\s*(;.*)?$/ ` recognizes such lines. Do you see how it
1090
- works? The part between the ((parentheses)) will match comments, and
1091
- the ` ? ` makes sure it also matches lines containing only whitespace.
1092
-
1093
- If the line is not a ((comment)), it may be a section header or a
1094
- regular option line. When it is a new section, an appropriate section
1095
- object is added to the array. When it is an option, an object
1096
- representing that option is added to the current (last) section.
1097
-
1098
- If a ((line)) matches none of these forms, the function throws an
1099
- error.
1094
+ There are two kinds of significant lines—section headers or property
1095
+ lines. When a line is a regular property, it is stored in the current
1096
+ section. When it is a section header, a new section object is created,
1097
+ and ` section ` is set to point at it.
1100
1098
1101
1099
{{index "caret character", "dollar sign", boundary}}
1102
1100
@@ -1115,6 +1113,13 @@ not break the pleasant chain of `if` forms, we assign the result of
1115
1113
the match to a binding and immediately use that assignment as the test
1116
1114
in the ` if ` statement.
1117
1115
1116
+ If a line is not a section header or a property, the function checks
1117
+ whether it is a comment or an emty line using the expression
1118
+ ` /^\s*(;.*)?$/ ` . Do you see how it works? The part between the
1119
+ ((parentheses)) will match comments, and the ` ? ` makes sure it also
1120
+ matches lines containing only whitespace. When a line doesn't match
1121
+ any of the expected forms, the function throws an exception.
1122
+
1118
1123
## International characters
1119
1124
1120
1125
{{index internationalization, Unicode, [ "regular expression", internationalization] }}
@@ -1313,6 +1318,7 @@ function verify(regexp, yes, no) {
1313
1318
}
1314
1319
}
1315
1320
```
1321
+
1316
1322
if}}
1317
1323
1318
1324
### Quoting style
0 commit comments