gpt4 book ai didi

d - 从 D 中的字符串流

转载 作者:行者123 更新时间:2023-12-02 08:37:52 25 4
gpt4 key购买 nike

有没有办法将string用作InputStream

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

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

现在我想使用 read() 系列函数来解析它以扫描不同的类型。

在纯 C 中有一个 sscanf 函数。在 C++ 中,我们有 std::stringstream。那么如何在 D 中获得类似的功能呢?

最佳答案

我认为两个可能的候选人是 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 类似,它会在读取字符串时使用它,但它根据格式字符串使用,而不是尝试使用尽可能多的字符串来转换为请求类型。然而,与 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

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.rangestd.algorithm 中)做很多,但是如果您要将字符串的内容转换为其他内容,如果内容是统一的,它们往往会工作得更好,因为你可以那样一次转换整个字符串,但你可以使用像 find 这样的函数和 until如果您需要以不同方式转换字符串的不同部分,请将字符串分开并分段转换。您还可以使用 splitter 在空格处拆分字符串,然后根据每个部分在字符串中的位置进行转换,但此时,您可能还不如使用 parseformattedRead。不过,您确实有很多选择。

如果您不是特别熟悉范围,那么我建议您阅读 http://ddili.org/ders/d.en/ranges.html因为这是我们目前拥有的最好的教程。

关于d - 从 D 中的字符串流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19481825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com