1 // Written in the D programming language.
2
3 /**
4 This is a submodule of $(MREF std, format).
5
6 It provides two functions for reading formatted input: $(LREF
7 unformatValue) and $(LREF formattedRead). The former reads a single
8 value. The latter reads several values at once and matches the
9 characters found between format specifiers.
10
11 Parameters are ignored, except for the ones consisting of a single
12 $(B '*'). See $(LREF formattedRead) for more information.
13
14 A space outside of a format specifier has a special meaning: it
15 matches any sequence of whitespace characters, not just a single
16 space.
17
18 The following combinations of format characters and types are
19 available:
20
21 $(BOOKTABLE ,
22 $(TR $(TH) $(TH s) $(TH c) $(TH d, u, b, o, x, X) $(TH e, E, f, g, G) $(TH r) $(TH compound))
23 $(TR $(TD `bool`) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
24 $(TR $(TD `null`) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
25 $(TR $(TD $(I integer)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)))
26 $(TR $(TD $(I floating point)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes) $(TD yes) $(TD $(MDASH)))
27 $(TR $(TD $(I character)) $(TD yes) $(TD yes) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))
28 $(TR $(TD $(I string)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
29 $(TR $(TD $(I array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
30 $(TR $(TD $(I associative array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))
31 )
32
33 Below are highlighted examples on how these combinations are used
34 with $(LREF unformatValue), however, they apply for $(LREF
35 formattedRead) also
36
37 Copyright: Copyright The D Language Foundation 2000-2013.
38
39 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
40
41 Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,
42 Andrei Alexandrescu), and Kenji Hara
43
44 Source: $(PHOBOSSRC std/format/read.d)
45 */
46 module std.format.read;
47
48 /// Booleans
49 @safe pure unittest
50 {
51 import std.format.spec : singleSpec;
52
53 auto str = "false";
54 auto spec = singleSpec("%s");
55 assert(str.unformatValue!bool(spec) == false);
56
57 str = "1";
58 spec = singleSpec("%d");
59 assert(str.unformatValue!bool(spec) == true);
60 }
61
62 /// Null values
63 @safe pure unittest
64 {
65 import std.format.spec : singleSpec;
66
67 auto str = "null";
68 auto spec = singleSpec("%s");
69 assert(str.unformatValue!(typeof(null))(spec) == null);
70 }
71
72 /// Integrals
73 @safe pure unittest
74 {
75 import std.format.spec : singleSpec;
76
77 // signed decimal values
78 auto str = "123";
79 auto spec = singleSpec("%s");
80 assert(str.unformatValue!int(spec) == 123);
81
82 // hexadecimal values
83 str = "ABC";
84 spec = singleSpec("%X");
85 assert(str.unformatValue!int(spec) == 2748);
86
87 // octal values
88 str = "11610";
89 spec = singleSpec("%o");
90 assert(str.unformatValue!int(spec) == 5000);
91
92 // raw read, depends on endianess
93 str = "\x75\x01";
94 spec = singleSpec("%r");
95 auto result = str.unformatValue!short(spec);
96 assert(result == 373 /* little endian */ || result == 29953 /* big endian */ );
97 }
98
99 /// Floating point numbers
100 @safe pure unittest
101 {
102 import std.format.spec : singleSpec;
103 import std.math.operations : isClose;
104
105 // natural notation
106 auto str = "123.456";
107 auto spec = singleSpec("%s");
108 assert(str.unformatValue!double(spec).isClose(123.456));
109
110 // scientific notation
111 str = "1e17";
112 spec = singleSpec("%e");
113 assert(str.unformatValue!double(spec).isClose(1e17));
114
115 // raw read, depends on endianess
116 str = "\x40\x00\x00\xBF";
117 spec = singleSpec("%r");
118 auto result = str.unformatValue!float(spec);
119 assert(isClose(result, -0.5) /* little endian */ || isClose(result, 2.0) /* big endian */ );
120 }
121
122 /// Characters
123 @safe pure unittest
124 {
125 import std.format.spec : singleSpec;
126
127 // only the first character is read
128 auto str = "abc";
129 auto spec = singleSpec("%s");
130 assert(str.unformatValue!char(spec) == 'a');
131
132 // using a numerical format character treats the read number as unicode code point
133 str = "65";
134 spec = singleSpec("%d");
135 assert(str.unformatValue!char(spec) == 'A');
136
137 str = "41";
138 spec = singleSpec("%x");
139 assert(str.unformatValue!char(spec) == 'A');
140
141 str = "10003";
142 spec = singleSpec("%d");
143 assert(str.unformatValue!dchar(spec) == '✓');
144 }
145
146 /// Arrays
147 @safe pure unittest
148 {
149 import std.format.spec : singleSpec;
150
151 // string value
152 string str = "aaa";
153 auto spec = singleSpec("%s");
154 assert(str.unformatValue!(dchar[])(spec) == "aaa"d);
155
156 // fixed size array with characters
157 str = "aaa";
158 spec = singleSpec("%s");
159 dchar[3] ret = ['a', 'a', 'a'];
160 assert(str.unformatValue!(dchar[3])(spec) == ret);
161
162 // dynamic array
163 str = "[1, 2, 3, 4]";
164 spec = singleSpec("%s");
165 assert(str.unformatValue!(int[])(spec) == [1, 2, 3, 4]);
166
167 // fixed size array with integers
168 str = "[1, 2, 3, 4]";
169 spec = singleSpec("%s");
170 int[4] ret2 = [1, 2, 3, 4];
171 assert(str.unformatValue!(int[4])(spec) == ret2);
172
173 // compound specifiers can be used for more control
174 str = "1,2,3";
175 spec = singleSpec("%(%s,%)");
176 assert(str.unformatValue!(int[])(spec) == [1, 2, 3]);
177
178 str = "cool";
179 spec = singleSpec("%(%c%)");
180 assert(str.unformatValue!(char[])(spec) == ['c', 'o', 'o', 'l']);
181 }
182
183 /// Associative arrays
184 @safe pure unittest
185 {
186 import std.format.spec : singleSpec;
187
188 // as single value
189 auto str = `["one": 1, "two": 2]`;
190 auto spec = singleSpec("%s");
191 assert(str.unformatValue!(int[string])(spec) == ["one": 1, "two": 2]);
192
193 // with compound specifier for more control
194 str = "1/1, 2/4, 3/9";
195 spec = singleSpec("%(%d/%d%|, %)");
196 assert(str.unformatValue!(int[int])(spec) == [1: 1, 2: 4, 3: 9]);
197 }
198
199 import std.format.spec : FormatSpec;
200 import std.format.internal.read;
201 import std.traits : isSomeString;
202
203 /**
204 Reads an input range according to a format string and stores the read
205 values into its arguments.
206
207 Format specifiers with format character $(B 'd'), $(B 'u') and $(B
208 'c') can take a $(B '*') parameter for skipping values.
209
210 The second version of `formattedRead` takes the format string as
211 template argument. In this case, it is checked for consistency at
212 compile-time.
213
214 Params:
215 r = an $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
216 where the formatted input is read from
217 fmt = a $(MREF_ALTTEXT format string, std,format)
218 args = a variadic list of arguments where the read values are stored
219 Range = the type of the input range `r`
220 Char = the character type used for `fmt`
221 Args = a variadic list of types of the arguments
222
223 Returns:
224 The number of variables filled. If the input range `r` ends early,
225 this number will be less than the number of variables provided.
226
227 Throws:
228 A $(REF_ALTTEXT FormatException, FormatException, std, format)
229 if reading did not succeed.
230
231 Note:
232 For backward compatibility the arguments `args` can be given as pointers
233 to that variable, but it is not recommended to do so, because this
234 option might be removed in the future.
235 */
formattedRead(Range,Char,Args...)236 uint formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, auto ref Args args)
237 {
238 import std.format : enforceFmt;
239 import std.range.primitives : empty;
240 import std.traits : isPointer;
241 import std.typecons : isTuple;
242
243 auto spec = FormatSpec!Char(fmt);
244 static if (!Args.length)
245 {
246 spec.readUpToNextSpec(r);
247 enforceFmt(spec.trailing.empty, "Trailing characters in formattedRead format string");
248 return 0;
249 }
250 else
251 {
252 enum hasPointer = isPointer!(typeof(args[0]));
253
254 // The function below accounts for '*' == fields meant to be
255 // read and skipped
256 void skipUnstoredFields()
257 {
258 for (;;)
259 {
260 spec.readUpToNextSpec(r);
261 if (spec.width != spec.DYNAMIC) break;
262 // must skip this field
263 skipData(r, spec);
264 }
265 }
266
267 skipUnstoredFields();
268 if (r.empty)
269 {
270 // Input is empty, nothing to read
271 return 0;
272 }
273
274 static if (hasPointer)
275 alias A = typeof(*args[0]);
276 else
277 alias A = typeof(args[0]);
278
279 static if (isTuple!A)
280 {
281 foreach (i, T; A.Types)
282 {
283 static if (hasPointer)
284 (*args[0])[i] = unformatValue!(T)(r, spec);
285 else
286 args[0][i] = unformatValue!(T)(r, spec);
287 skipUnstoredFields();
288 }
289 }
290 else
291 {
292 static if (hasPointer)
293 *args[0] = unformatValue!(A)(r, spec);
294 else
295 args[0] = unformatValue!(A)(r, spec);
296 }
297 return 1 + formattedRead(r, spec.trailing, args[1 .. $]);
298 }
299 }
300
301 /// ditto
302 uint formattedRead(alias fmt, Range, Args...)(auto ref Range r, auto ref Args args)
303 if (isSomeString!(typeof(fmt)))
304 {
305 import std.format : checkFormatException;
306
307 alias e = checkFormatException!(fmt, Args);
308 static assert(!e, e);
309 return .formattedRead(r, fmt, args);
310 }
311
312 ///
313 @safe pure unittest
314 {
315 string object;
316 char cmp;
317 int value;
318
319 assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3);
320 assert(object == "angle");
321 assert(cmp == '<');
322 assert(value == 36);
323
324 // reading may end early:
325 assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2);
326 assert(object == "length");
327 assert(cmp == '>');
328 // value is not changed:
329 assert(value == 36);
330 }
331
332 /// The format string can be checked at compile-time:
333 @safe pure unittest
334 {
335 string a;
336 int b;
337 double c;
338
339 assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3);
340 assert(a == "hello");
341 assert(b == 124);
342 assert(c == 34.5);
343 }
344
345 /// Skipping values
346 @safe pure unittest
347 {
348 string item;
349 double amount;
350
351 assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2);
352 assert(item == "orange");
353 assert(amount == 15.25);
354
355 // can also be used with tuples
356 import std.typecons : Tuple;
357
358 Tuple!(int, float) t;
359 char[] line = "1 7643 2.125".dup;
360 formattedRead(line, "%s %*u %s", t);
361 assert(t[0] == 1 && t[1] == 2.125);
362 }
363
364 @safe unittest
365 {
366 import std.math.operations : isClose;
367 import std.math.traits : isNaN;
368 import std.range.primitives : empty;
369
370 string s = " 1.2 3.4 ";
371 double x, y, z;
372 assert(formattedRead(s, " %s %s %s ", x, y, z) == 2);
373 assert(s.empty);
374 assert(isClose(x, 1.2));
375 assert(isClose(y, 3.4));
376 assert(isNaN(z));
377 }
378
379 // for backwards compatibility
380 @safe pure unittest
381 {
382 string s = "hello!124:34.5";
383 string a;
384 int b;
385 double c;
386 formattedRead(s, "%s!%s:%s", &a, &b, &c);
387 assert(a == "hello" && b == 124 && c == 34.5);
388
389 // mix pointers and auto-ref
390 s = "world!200:42.25";
391 formattedRead(s, "%s!%s:%s", a, &b, &c);
392 assert(a == "world" && b == 200 && c == 42.25);
393
394 s = "world1!201:42.5";
395 formattedRead(s, "%s!%s:%s", &a, &b, c);
396 assert(a == "world1" && b == 201 && c == 42.5);
397
398 s = "world2!202:42.75";
399 formattedRead(s, "%s!%s:%s", a, b, &c);
400 assert(a == "world2" && b == 202 && c == 42.75);
401 }
402
403 // for backwards compatibility
404 @safe pure unittest
405 {
406 import std.math.operations : isClose;
407 import std.math.traits : isNaN;
408 import std.range.primitives : empty;
409
410 string s = " 1.2 3.4 ";
411 double x, y, z;
412 assert(formattedRead(s, " %s %s %s ", &x, &y, &z) == 2);
413 assert(s.empty);
414 assert(isClose(x, 1.2));
415 assert(isClose(y, 3.4));
416 assert(isNaN(z));
417 }
418
419 @safe unittest
420 {
421 string s = "hello!124:34.5";
422 string a;
423 int b;
424 double c;
425 formattedRead(s, "%s!%s:%s", &a, &b, &c);
426 assert(a == "hello" && b == 124 && c == 34.5);
427 }
428
429 @safe pure unittest
430 {
431 string line;
432
433 bool f1;
434
435 line = "true";
436 formattedRead(line, "%s", &f1);
437 assert(f1);
438
439 line = "TrUE";
440 formattedRead(line, "%s", &f1);
441 assert(f1);
442
443 line = "false";
444 formattedRead(line, "%s", &f1);
445 assert(!f1);
446
447 line = "fALsE";
448 formattedRead(line, "%s", &f1);
449 assert(!f1);
450
451 line = "1";
452 formattedRead(line, "%d", &f1);
453 assert(f1);
454
455 line = "-1";
456 formattedRead(line, "%d", &f1);
457 assert(f1);
458
459 line = "0";
460 formattedRead(line, "%d", &f1);
461 assert(!f1);
462
463 line = "-0";
464 formattedRead(line, "%d", &f1);
465 assert(!f1);
466 }
467
468 @safe pure unittest
469 {
470 union B
471 {
472 char[int.sizeof] untyped;
473 int typed;
474 }
475
476 B b;
477 b.typed = 5;
478 char[] input = b.untyped[];
479 int witness;
480 formattedRead(input, "%r", &witness);
481 assert(witness == b.typed);
482 }
483
484 @safe pure unittest
485 {
486 union A
487 {
488 char[float.sizeof] untyped;
489 float typed;
490 }
491
492 A a;
493 a.typed = 5.5;
494 char[] input = a.untyped[];
495 float witness;
496 formattedRead(input, "%r", &witness);
497 assert(witness == a.typed);
498 }
499
500 @safe pure unittest
501 {
502 import std.typecons : Tuple;
503
504 char[] line = "1 2".dup;
505 int a, b;
506 formattedRead(line, "%s %s", &a, &b);
507 assert(a == 1 && b == 2);
508
509 line = "10 2 3".dup;
510 formattedRead(line, "%d ", &a);
511 assert(a == 10);
512 assert(line == "2 3");
513
514 Tuple!(int, float) t;
515 line = "1 2.125".dup;
516 formattedRead(line, "%d %g", &t);
517 assert(t[0] == 1 && t[1] == 2.125);
518
519 line = "1 7643 2.125".dup;
520 formattedRead(line, "%s %*u %s", &t);
521 assert(t[0] == 1 && t[1] == 2.125);
522 }
523
524 @safe pure unittest
525 {
526 string line;
527
528 char c1, c2;
529
530 line = "abc";
531 formattedRead(line, "%s%c", &c1, &c2);
532 assert(c1 == 'a' && c2 == 'b');
533 assert(line == "c");
534 }
535
536 @safe pure unittest
537 {
538 string line;
539
540 line = "[1,2,3]";
541 int[] s1;
542 formattedRead(line, "%s", &s1);
543 assert(s1 == [1,2,3]);
544 }
545
546 @safe pure unittest
547 {
548 string line;
549
550 line = "[1,2,3]";
551 int[] s1;
552 formattedRead(line, "[%(%s,%)]", &s1);
553 assert(s1 == [1,2,3]);
554
555 line = `["hello", "world"]`;
556 string[] s2;
557 formattedRead(line, "[%(%s, %)]", &s2);
558 assert(s2 == ["hello", "world"]);
559
560 line = "123 456";
561 int[] s3;
562 formattedRead(line, "%(%s %)", &s3);
563 assert(s3 == [123, 456]);
564
565 line = "h,e,l,l,o; w,o,r,l,d";
566 string[] s4;
567 formattedRead(line, "%(%(%c,%); %)", &s4);
568 assert(s4 == ["hello", "world"]);
569 }
570
571 @safe pure unittest
572 {
573 import std.exception : assertThrown;
574
575 string line;
576
577 int[4] sa1;
578 line = `[1,2,3,4]`;
579 formattedRead(line, "%s", &sa1);
580 assert(sa1 == [1,2,3,4]);
581
582 int[4] sa2;
583 line = `[1,2,3]`;
584 assertThrown(formattedRead(line, "%s", &sa2));
585
586 int[4] sa3;
587 line = `[1,2,3,4,5]`;
588 assertThrown(formattedRead(line, "%s", &sa3));
589 }
590
591 @safe pure unittest
592 {
593 import std.exception : assertThrown;
594 import std.format : FormatException;
595
596 string input;
597
598 int[4] sa1;
599 input = `[1,2,3,4]`;
600 formattedRead(input, "[%(%s,%)]", &sa1);
601 assert(sa1 == [1,2,3,4]);
602
603 int[4] sa2;
604 input = `[1,2,3]`;
605 assertThrown!FormatException(formattedRead(input, "[%(%s,%)]", &sa2));
606 }
607
608 @safe pure unittest
609 {
610 string line;
611
612 string s1, s2;
613
614 line = "hello, world";
615 formattedRead(line, "%s", &s1);
616 assert(s1 == "hello, world", s1);
617
618 line = "hello, world;yah";
619 formattedRead(line, "%s;%s", &s1, &s2);
620 assert(s1 == "hello, world", s1);
621 assert(s2 == "yah", s2);
622
623 line = `['h','e','l','l','o']`;
624 string s3;
625 formattedRead(line, "[%(%s,%)]", &s3);
626 assert(s3 == "hello");
627
628 line = `"hello"`;
629 string s4;
630 formattedRead(line, "\"%(%c%)\"", &s4);
631 assert(s4 == "hello");
632 }
633
634 @safe pure unittest
635 {
636 string line;
637
638 string[int] aa1;
639 line = `[1:"hello", 2:"world"]`;
640 formattedRead(line, "%s", &aa1);
641 assert(aa1 == [1:"hello", 2:"world"]);
642
643 int[string] aa2;
644 line = `{"hello"=1; "world"=2}`;
645 formattedRead(line, "{%(%s=%s; %)}", &aa2);
646 assert(aa2 == ["hello":1, "world":2]);
647
648 int[string] aa3;
649 line = `{[hello=1]; [world=2]}`;
650 formattedRead(line, "{%([%(%c%)=%s]%|; %)}", &aa3);
651 assert(aa3 == ["hello":1, "world":2]);
652 }
653
654 // test rvalue using
655 @safe pure unittest
656 {
657 string[int] aa1;
658 formattedRead!("%s")(`[1:"hello", 2:"world"]`, aa1);
659 assert(aa1 == [1:"hello", 2:"world"]);
660
661 int[string] aa2;
662 formattedRead(`{"hello"=1; "world"=2}`, "{%(%s=%s; %)}", aa2);
663 assert(aa2 == ["hello":1, "world":2]);
664 }
665
666 /**
667 Reads a value from the given _input range and converts it according to a
668 format specifier.
669
670 Params:
671 input = the $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
672 to read from
673 spec = a $(MREF_ALTTEXT format string, std,format)
674 T = type to return
675 Range = the type of the input range `input`
676 Char = the character type used for `spec`
677
678 Returns:
679 A value from `input` of type `T`.
680
681 Throws:
682 A $(REF_ALTTEXT FormatException, FormatException, std, format)
683 if reading did not succeed.
684
685 See_Also:
686 $(REF parse, std, conv) and $(REF to, std, conv)
687 */
unformatValue(T,Range,Char)688 T unformatValue(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char spec)
689 {
690 return unformatValueImpl!T(input, spec);
691 }
692
693 ///
694 @safe pure unittest
695 {
696 import std.format.spec : singleSpec;
697
698 string s = "42";
699 auto spec = singleSpec("%s");
700 assert(unformatValue!int(s, spec) == 42);
701 }
702
703 // https://issues.dlang.org/show_bug.cgi?id=7241
704 @safe pure unittest
705 {
706 string input = "a";
707 auto spec = FormatSpec!char("%s");
708 spec.readUpToNextSpec(input);
709 auto result = unformatValue!(dchar[1])(input, spec);
710 assert(result[0] == 'a');
711 }
712
713 // https://issues.dlang.org/show_bug.cgi?id=20393
714 @safe pure unittest
715 {
716 import std.exception : assertThrown;
717 string str = "foo 12a-buzz";
718 string a, c;
719 int b;
720 assertThrown(formattedRead(str, "%s %d-%s", &a, &b, &c));
721 }
722
723 // https://issues.dlang.org/show_bug.cgi?id=18051
724 @safe pure unittest
725 {
726 import std.format : format;
727
728 enum Op { lt, gt, eq }
729
730 auto s = format!"%s"(Op.lt);
731 Op op;
732 assert(formattedRead!"%s"(s, op) == 1);
733 assert(op == Op.lt);
734 }
735