有没有办法使用的方式string为InputStream?
假设我已经从网络下载了文本数据:
string str = to!string(std.net.curl.get("www.someurl.com/data.txt"));
Run Code Online (Sandbox Code Playgroud)
现在我想使用read()-family函数解析它以扫描不同类型.
在普通C中有一个sscanf功能.在C++中我们有std::stringstream.那么如何在D中获得类似的功能呢?
我认为两个可能的候选者是std.conv.parse和std.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);
}
Run Code Online (Sandbox Code Playgroud)
formattedRead另一方面更接近sscanf.你必须给它一个格式字符串,它将返回它读取的元素数量.类似于parse,它会在读取字符串时使用字符串,但它会根据格式字符串消耗,而不是尝试消耗尽可能多的字符串,因为它可以转换为一个请求类型.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);
}
Run Code Online (Sandbox Code Playgroud)
其他替代方案是简单地利用字符串是范围的事实,并使用Phobos中的各种基于范围的函数来以任何适合您正在做的方式使用字符串.例如,如果你知道你的字符串纯粹由用空格分隔的整数组成,你可以int通过执行将它们转换为一个范围
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]));
}
Run Code Online (Sandbox Code Playgroud)
如果你想要一个阵列而不是一个懒惰的范围,你可以简单地调用std.array.array该范围.
你可以做很多与各种基于范围的函数(其中主要是中std.range和std.algorithm),但如果你将一个字符串的内容到别的东西,他们会倾向于工作,如果内容好是统一的,因为你可以一次转换整个字符串,但是如果你需要以不同的方式转换字符串的不同部分,你可以使用像find和until这样的函数来分开并将它转换成碎片.您还可以使用splitter在空格上拆分字符串,然后根据字符串中的位置转换每个部分,但此时,您可能也可以使用parse或formattedRead.你确实有很多选择.
如果你不是特别熟悉范围,那么我建议你阅读http://ddili.org/ders/d.en/ranges.html,因为这是我们目前最好的教程.
| 归档时间: |
|
| 查看次数: |
401 次 |
| 最近记录: |