Wolfgang Thallergcc 15.1.0ada185d1 year agoHistory
884 lines · 22.2 KB · D
RawDownload
// Written in the D programming language. /**This is a submodule of $(MREF std, format). It provides two functions for reading formatted input: $(LREFunformatValue) and $(LREF formattedRead). The former reads a singlevalue. The latter reads several values at once and matches thecharacters found between format specifiers. Parameters are ignored, except for the ones consisting of a single$(B '*'). See $(LREF formattedRead) for more information. A space outside of a format specifier has a special meaning: itmatches any sequence of whitespace characters, not just a singlespace. The following combinations of format characters and types areavailable: $(BOOKTABLE ,$(TR $(TH) $(TH s) $(TH c) $(TH d, u, b, o, x, X) $(TH e, E, f, g, G) $(TH r) $(TH compound))$(TR $(TD `bool`) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))$(TR $(TD `null`) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))$(TR $(TD $(I integer)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)) $(TD yes) $(TD $(MDASH)))$(TR $(TD $(I floating point)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes) $(TD yes) $(TD $(MDASH)))$(TR $(TD $(I character)) $(TD yes) $(TD yes) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)))$(TR $(TD $(I string)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))$(TR $(TD $(I array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))$(TR $(TD $(I associative array)) $(TD yes) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD $(MDASH)) $(TD yes))) Below are highlighted examples on how these combinations are usedwith $(LREF unformatValue), however, they apply for $(LREFformattedRead) also Copyright: Copyright The D Language Foundation 2000-2013. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com,Andrei Alexandrescu), and Kenji Hara Source: $(PHOBOSSRC std/format/read.d) */module std.format.read; /// Booleans@safe pure unittest{    import std.format.spec : singleSpec;     auto str = "false";    auto spec = singleSpec("%s");    assert(str.unformatValue!bool(spec) == false);     str = "1";    spec = singleSpec("%d");    assert(str.unformatValue!bool(spec) == true);} /// Null values@safe pure unittest{    import std.format.spec : singleSpec;     auto str = "null";    auto spec = singleSpec("%s");    assert(str.unformatValue!(typeof(null))(spec) == null);} /// Integrals@safe pure unittest{    import std.format.spec : singleSpec;     // signed decimal values    auto str = "123";    auto spec = singleSpec("%s");    assert(str.unformatValue!int(spec) == 123);     // hexadecimal values    str = "ABC";    spec = singleSpec("%X");    assert(str.unformatValue!int(spec) == 2748);     // octal values    str = "11610";    spec = singleSpec("%o");    assert(str.unformatValue!int(spec) == 5000);     // raw read, depends on endianess    str = "\x75\x01";    spec = singleSpec("%r");    auto result = str.unformatValue!short(spec);    assert(result == 373 /* little endian */ || result == 29953 /* big endian */ );} /// Floating point numbers@safe pure unittest{    import std.format.spec : singleSpec;    import std.math.operations : isClose;     // natural notation    auto str = "123.456";    auto spec = singleSpec("%s");    assert(str.unformatValue!double(spec).isClose(123.456));     // scientific notation    str = "1e17";    spec = singleSpec("%e");    assert(str.unformatValue!double(spec).isClose(1e17));     // raw read, depends on endianess    str = "\x40\x00\x00\xBF";    spec = singleSpec("%r");    auto result = str.unformatValue!float(spec);    assert(isClose(result, -0.5) /* little endian */ || isClose(result, 2.0) /* big endian */ );} /// Characters@safe pure unittest{    import std.format.spec : singleSpec;     // only the first character is read    auto str = "abc";    auto spec = singleSpec("%s");    assert(str.unformatValue!char(spec) == 'a');     // using a numerical format character treats the read number as unicode code point    str = "65";    spec = singleSpec("%d");    assert(str.unformatValue!char(spec) == 'A');     str = "41";    spec = singleSpec("%x");    assert(str.unformatValue!char(spec) == 'A');     str = "10003";    spec = singleSpec("%d");    assert(str.unformatValue!dchar(spec) == '✓');} /// Arrays@safe pure unittest{    import std.format.spec : singleSpec;     // string value    string str = "aaa";    auto spec = singleSpec("%s");    assert(str.unformatValue!(dchar[])(spec) == "aaa"d);     // fixed size array with characters    str = "aaa";    spec = singleSpec("%s");    dchar[3] ret = ['a', 'a', 'a'];    assert(str.unformatValue!(dchar[3])(spec) == ret);     // dynamic array    str = "[1, 2, 3, 4]";    spec = singleSpec("%s");    assert(str.unformatValue!(int[])(spec) == [1, 2, 3, 4]);     // fixed size array with integers    str = "[1, 2, 3, 4]";    spec = singleSpec("%s");    int[4] ret2 = [1, 2, 3, 4];    assert(str.unformatValue!(int[4])(spec) == ret2);     // compound specifiers can be used for more control    str = "1,2,3";    spec = singleSpec("%(%s,%)");    assert(str.unformatValue!(int[])(spec) == [1, 2, 3]);     str = "cool";    spec = singleSpec("%(%c%)");    assert(str.unformatValue!(char[])(spec) == ['c', 'o', 'o', 'l']);} /// Associative arrays@safe pure unittest{    import std.format.spec : singleSpec;     // as single value    auto str = `["one": 1, "two": 2]`;    auto spec = singleSpec("%s");    assert(str.unformatValue!(int[string])(spec) == ["one": 1, "two": 2]);     // with compound specifier for more control    str = "1/1, 2/4, 3/9";    spec = singleSpec("%(%d/%d%|, %)");    assert(str.unformatValue!(int[int])(spec) == [1: 1, 2: 4, 3: 9]);} import std.format.spec : FormatSpec;import std.format.internal.read;import std.meta : allSatisfy;import std.traits : isSomeString, isType; /**Reads an input range according to a format string and stores the readvalues into its arguments. Format specifiers with format character $(B 'd'), $(B 'u') and $(B'c') can take a $(B '*') parameter for skipping values. The second version of `formattedRead` takes the format string astemplate argument. In this case, it is checked for consistency atcompile-time. Params:    r = an $(REF_ALTTEXT input range, isInputRange, std, range, primitives),        where the formatted input is read from    fmt = a $(MREF_ALTTEXT format string, std,format)    args = a variadic list of arguments where the read values are stored    Range = the type of the input range `r`    Char = the character type used for `fmt`    Args = a variadic list of types of the arguments Returns:    The number of variables filled. If the input range `r` ends early,    this number will be less than the number of variables provided. Throws:    A $(REF_ALTTEXT FormatException, FormatException, std, format)    if reading did not succeed. Note:    For backward compatibility the arguments `args` can be given as pointers    to that variable, but it is not recommended to do so, because this    option might be removed in the future. */uint formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, auto ref Args args){    import std.format : enforceFmt;    import std.range.primitives : empty;    import std.traits : isPointer;    import std.typecons : isTuple;     auto spec = FormatSpec!Char(fmt);    static if (!Args.length)    {        spec.readUpToNextSpec(r);        enforceFmt(spec.trailing.empty, "Trailing characters in formattedRead format string");        return 0;    }    else    {        enum hasPointer = isPointer!(typeof(args[0]));         // The function below accounts for '*' == fields meant to be        // read and skipped        void skipUnstoredFields()        {            for (;;)            {                spec.readUpToNextSpec(r);                if (spec.width != spec.DYNAMIC) break;                // must skip this field                skipData(r, spec);            }        }         skipUnstoredFields();        if (r.empty)        {            // Input is empty, nothing to read            return 0;        }         static if (hasPointer)            alias A = typeof(*args[0]);        else            alias A = typeof(args[0]);         static if (isTuple!A)        {            foreach (i, T; A.Types)            {                static if (hasPointer)                    (*args[0])[i] = unformatValue!(T)(r, spec);                else                    args[0][i] = unformatValue!(T)(r, spec);                skipUnstoredFields();            }        }        else        {            static if (hasPointer)                *args[0] = unformatValue!(A)(r, spec);            else                args[0] = unformatValue!(A)(r, spec);        }        return 1 + formattedRead(r, spec.trailing, args[1 .. $]);    }} /// dittouint formattedRead(alias fmt, Range, Args...)(auto ref Range r, auto ref Args args)if (!isType!fmt && isSomeString!(typeof(fmt))){    import std.format : checkFormatException;    import std.meta : staticMap;    import std.typecons : Tuple;      // formattedRead supports std.typecons.Tuple    // however, checkFormatException does not    // this means that all std.typecons.Tuple's types in Args must be unwrapped    // and passed to checkFormatException    template Flatten(T)    {        static if (is(T : Tuple!Args, Args...))            alias Flatten = Args;        else            alias Flatten = T;    }     alias e = checkFormatException!(fmt, staticMap!(Flatten, Args));    static assert(!e, e);    return .formattedRead(r, fmt, args);} ///@safe pure unittest{    string object;    char cmp;    int value;     assert(formattedRead("angle < 36", "%s %c %d", object, cmp, value) == 3);    assert(object == "angle");    assert(cmp == '<');    assert(value == 36);     // reading may end early:    assert(formattedRead("length >", "%s %c %d", object, cmp, value) == 2);    assert(object == "length");    assert(cmp == '>');    // value is not changed:    assert(value == 36);} /// The format string can be checked at compile-time:@safe pure unittest{    string a;    int b;    double c;     assert("hello!124:34.5".formattedRead!"%s!%s:%s"(a, b, c) == 3);    assert(a == "hello");    assert(b == 124);    assert(c == 34.5);} /// Skipping values@safe pure unittest{    string item;    double amount;     assert("orange: (12%) 15.25".formattedRead("%s: (%*d%%) %f", item, amount) == 2);    assert(item == "orange");    assert(amount == 15.25);     // can also be used with tuples    import std.typecons : Tuple;     Tuple!(int, float) t;    char[] line = "1 7643 2.125".dup;    formattedRead(line, "%s %*u %s", t);    assert(t[0] == 1 && t[1] == 2.125);} @safe pure unittest{    string hello;    string world;     assert("hello ignore world".formattedRead("%s %*s %s", hello, world) == 2);    assert(hello == "hello");    assert(world == "world");} // https://issues.dlang.org/show_bug.cgi?id=23600@safe pure unittest{    import std.typecons : Tuple, tuple;     string h, w;    Tuple!(int, float) t;     assert("hello 1 2.34 world".formattedRead!"%s %d %f %s"(h, t, w) == 3);    assert(h == "hello");    assert(t == tuple(1, 2.34f));    assert(w == "world");} @safe unittest{    import std.math.operations : isClose;    import std.math.traits : isNaN;    import std.range.primitives : empty;     string s = " 1.2 3.4 ";    double x, y, z;    assert(formattedRead(s, " %s %s %s ", x, y, z) == 2);    assert(s.empty);    assert(isClose(x, 1.2));    assert(isClose(y, 3.4));    assert(isNaN(z));} // for backwards compatibility@safe pure unittest{    string s = "hello!124:34.5";    string a;    int b;    double c;    formattedRead(s, "%s!%s:%s", &a, &b, &c);    assert(a == "hello" && b == 124 && c == 34.5);     // mix pointers and auto-ref    s = "world!200:42.25";    formattedRead(s, "%s!%s:%s", a, &b, &c);    assert(a == "world" && b == 200 && c == 42.25);     s = "world1!201:42.5";    formattedRead(s, "%s!%s:%s", &a, &b, c);    assert(a == "world1" && b == 201 && c == 42.5);     s = "world2!202:42.75";    formattedRead(s, "%s!%s:%s", a, b, &c);    assert(a == "world2" && b == 202 && c == 42.75);} // for backwards compatibility@safe pure unittest{    import std.math.operations : isClose;    import std.math.traits : isNaN;    import std.range.primitives : empty;     string s = " 1.2 3.4 ";    double x, y, z;    assert(formattedRead(s, " %s %s %s ", &x, &y, &z) == 2);    assert(s.empty);    assert(isClose(x, 1.2));    assert(isClose(y, 3.4));    assert(isNaN(z));} @safe unittest{    string s = "hello!124:34.5";    string a;    int b;    double c;    formattedRead(s, "%s!%s:%s", &a, &b, &c);    assert(a == "hello" && b == 124 && c == 34.5);} @safe pure unittest{    string line;     bool f1;     line = "true";    formattedRead(line, "%s", &f1);    assert(f1);     line = "TrUE";    formattedRead(line, "%s", &f1);    assert(f1);     line = "false";    formattedRead(line, "%s", &f1);    assert(!f1);     line = "fALsE";    formattedRead(line, "%s", &f1);    assert(!f1);     line = "1";    formattedRead(line, "%d", &f1);    assert(f1);     line = "-1";    formattedRead(line, "%d", &f1);    assert(f1);     line = "0";    formattedRead(line, "%d", &f1);

Lines 1–500 of 884.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t