来自D中字符串的流

来自D中字符串的流,d,D,有没有办法将字符串用作输入流 假设我从网络下载了文本数据: string str = to!string(std.net.curl.get("www.someurl.com/data.txt")); 现在我想使用read()-用于扫描不同类型的系列函数来解析它 在普通C中有一个sscanf函数。在C++中,我们有 STD::StrugStuts。 那么,如何在D中获得类似的功能呢?我认为两个可能的候选者是和 parse允许您通过多次调用将字符串解析为多种类型。它通过ref获取字符串,并在将其转

有没有办法将
字符串
用作
输入流

假设我从网络下载了文本数据:

string str = to!string(std.net.curl.get("www.someurl.com/data.txt"));
现在我想使用
read()
-用于扫描不同类型的系列函数来解析它

在普通C中有一个
sscanf
函数。在C++中,我们有<代码> STD::StrugStuts。
那么,如何在D中获得类似的功能呢?

我认为两个可能的候选者是和

parse
允许您通过多次调用将字符串解析为多种类型。它通过
ref
获取字符串,并在将其转换为请求的类型时尽可能多地消耗字符串。当您希望通过一系列调用使用字符串,而不是一次转换所有字符串时,它工作得特别好。e、 g

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
类似,它将在读取字符串时使用该字符串,但它根据格式字符串进行使用,而不是尝试使用尽可能多的字符串来转换为请求类型。然而,与
sscanf
不同,
formattedRead
是类型安全的,并且知道传递给它的变量的类型。因此,您可以使用
%s
将其转换为给定变量的类型,而不必为所使用的变量类型指定特定的标志(尽管如果您愿意,您仍然可以使用更特定的标志,就像使用
writefln
一样)。e、 g

其他替代方法是简单地利用字符串是范围的事实,并使用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

您可以使用各种基于范围的函数(主要函数位于和中),但如果要将字符串的内容转换为其他内容,如果内容是统一的,它们的工作效果会更好,因为您可以通过这种方式一次转换整个字符串,但是,如果需要以不同的方式转换字符串的不同部分,可以使用诸如和之类的函数将字符串分离并将其转换为片段。您也可以使用
splitter
在空白处拆分字符串,然后根据每个片段在字符串中的位置进行转换,但此时,您可能只需要使用
parse
formattedRead
。不过你有很多选择


如果您对范围不是特别熟悉,那么我建议您阅读,因为这是目前关于范围的最佳教程。

std.net.curl没有输入流变体吗?
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]));
}