2

stringとして使用する方法はありInputStreamますか?

ネットワークからテキスト データをダウンロードしたとします。

string str = to!string(std.net.curl.get("www.someurl.com/data.txt"));

read()そして今、さまざまなタイプをスキャンするために -family 関数を使用して解析したいと考えています。

プレーンCにはsscanf関数があります。C++ ではstd::stringstream. では、D で同様の機能を取得するにはどうすればよいでしょうか。

4

1 に答える 1

6

2つの可能性のある候補はstd.conv.parsestd.format.formattedReadだと思います。

parse文字列を複数回呼び出すことで、文字列をさまざまなタイプとして解析できます。文字列refを取得し、要求された型に変換するときにできるだけ多くの文字列を消費します。文字列を一度に変換するのではなく、一連の呼び出しで文字列を消費したい場合に特に効果的です。例えば

import std.array;
import std.conv;
import std.math;
import std.string;

void main()
{
    auto str = "10 12.22 3.14159 22";
    auto a = parse!int(str);
    assert(a == 10);
    assert(str == " 12.22 3.14159 22");

    str = str.stripLeft();
    assert(str == "12.22 3.14159 22");

    auto b = parse!double(str);
    assert(approxEqual(b, 12.22));
    assert(str == " 3.14159 22");

    str = str.stripLeft();
    assert(str == "3.14159 22");

    auto c = parse!long(str);
    assert(c == 3);
    assert(str == ".14159 22");

    str = str.stripLeft();
    assert(str == ".14159 22");

    auto d = parse!float(str);
    assert(approxEqual(d, 0.14159));
    assert(str == " 22");

    str = str.stripLeft();
    assert(str == "22");

    auto e = parse!int(str);
    assert(e == 22);
    assert(str.empty);
}

formattedRead一方、 に近いsscanfです。フォーマット文字列を指定する必要があり、読み取った要素の数が返されます。と同様にparse、読み取り時に文字列を消費しますが、できるだけ多くの文字列を消費して 1 つのリクエスト タイプに変換しようとするのではなく、フォーマット文字列に従って消費します。sscanfただし、タイプ セーフとは異なりformattedRead、渡される変数のタイプを認識します。したがって、使用%sする変数の型に固有のフラグを指定するのではなく、指定された変数の型に変換するためにそれを使用できます (必要に応じて、より具体的なフラグを使用することもできます - のようにwritefln)。例えば

import std.array;
import std.format;
import std.math;
import std.string;

void main()
{
    auto str = "10 12.22 3.14159 22";
    int a;
    double b;
    long c;
    auto numRead1 = formattedRead(str, "%s %s %s", &a, &b, &c);
    assert(numRead1 == 3);
    assert(a == 10);
    assert(approxEqual(b, 12.22));
    assert(c == 3);
    assert(str == ".14159 22");

    float d;
    int e;
    auto numRead2 = formattedRead(str, "%s %s", &d, &e);
    assert(numRead2 == 2);
    assert(approxEqual(d, 0.14159));
    assert(e == 22);
    assert(str.empty);
}

他の方法としては、文字列が範囲であるという事実を単純に利用し、Phobos のさまざまな範囲ベースの関数を使用して、実行している方法に適した方法で文字列を消費することです。たとえば、文字列が空白で区切られた純粋な整数で構成されていることがわかっている場合は、次のようにint遅延して s の範囲に変換できます。

import std.algorithm;
import std.array;
import std.conv;
import std.string;

void main()
{
    auto str = "42 22 9 77 46 2 1 0 99";
    auto range = std.array.splitter(str).map!(a => to!int(a))();
    assert(equal(range, [42, 22, 9, 77, 46, 2, 1, 0, 99]));
}

また、遅延範囲の代わりに配列が必要な場合は、単純std.array.arrayに範囲を呼び出すことができます。

さまざまな範囲ベースの関数 (主なものはstd.rangeおよびstd.algorithmにあります) を使用して多くのことができますが、文字列の内容を別のものに変換する場合、内容がこのように文字列全体を一度に変換できるため、均一ですが、文字列のさまざまな部分を別々に変換する必要がある場合は、や などの関数を使用して文字列を分離し、分割して変換することができます。を使用して、文字列を空白で分割し、文字列内の場所に従って各部分を変換することもできますが、その時点では、単にorを使用することもできます。ただし、かなり多くのオプションがあります。finduntilsplitterparseformattedRead

範囲に特に精通していない場合は、http://ddili.org/ders/d.en/ranges.htmlを読むことをお勧めします。これは、現時点で私たちが持っている最高のチュートリアルです。

于 2013-10-20T22:01:43.673 に答える