mirror of
https://github.com/dlang/phobos.git
synced 2025-04-26 13:10:35 +03:00
stdio: add readfln and File.readfln
Compared to readf, these functions provide a less error-prone way to read a single line of formatted input. Fixes #10370
This commit is contained in:
parent
0d724aa0c8
commit
4a91ed7033
2 changed files with 150 additions and 0 deletions
6
changelog/readfln.dd
Normal file
6
changelog/readfln.dd
Normal file
|
@ -0,0 +1,6 @@
|
|||
Added `readfln` and `File.readfln` to `std.stdio`
|
||||
|
||||
These functions read a single line of input and parse it using a format string.
|
||||
Unlike `readf`, they will not accidentally read multiple lines if the user
|
||||
forgets to include a line terminator in the format string—a common mistake for
|
||||
beginners.
|
144
std/stdio.d
144
std/stdio.d
|
@ -18,6 +18,7 @@ $(TR $(TD Reading) $(TD
|
|||
$(MYREF chunks)
|
||||
$(MYREF lines)
|
||||
$(MYREF readf)
|
||||
$(MYREF readfln)
|
||||
$(MYREF readln)
|
||||
))
|
||||
$(TR $(TD Writing) $(TD
|
||||
|
@ -2094,6 +2095,85 @@ $(CONSOLE
|
|||
"Unexpected '\\n' when converting from type LockingTextReader to type int");
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a line from the file and parses it using $(REF formattedRead, std,format,read).
|
||||
|
||||
Params:
|
||||
format = The $(MREF_ALTTEXT format string, std,format). When passed as a
|
||||
compile-time argument, the string will be statically checked against the
|
||||
argument types passed.
|
||||
data = Items to be read.
|
||||
|
||||
Returns: Same as `formattedRead`: the number of variables filled. If the
|
||||
input ends early, this number will be less that the number of variables
|
||||
provided.
|
||||
|
||||
Example:
|
||||
---
|
||||
// sum_rows.d
|
||||
void main()
|
||||
{
|
||||
import std.stdio;
|
||||
auto f = File("input");
|
||||
int a, b, c;
|
||||
while (f.readfln("%d %d %d", a, b, c) == 3)
|
||||
{
|
||||
writeln(a + b + c);
|
||||
}
|
||||
}
|
||||
---
|
||||
$(CONSOLE
|
||||
% cat << EOF > input
|
||||
1 2 3
|
||||
4 5 6
|
||||
7 8 9
|
||||
EOF
|
||||
% rdmd sum_rows.d
|
||||
6
|
||||
15
|
||||
24
|
||||
)
|
||||
*/
|
||||
uint readfln(alias format, Data...)(auto ref Data data)
|
||||
if (isSomeString!(typeof(format)))
|
||||
{
|
||||
import std.format : checkFormatException;
|
||||
|
||||
alias e = checkFormatException!(format, Data);
|
||||
static assert(!e, e);
|
||||
return this.readfln(format, data);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
uint readfln(Data...)(scope const(char)[] format, auto ref Data data)
|
||||
{
|
||||
import std.format.read : formattedRead;
|
||||
import std.string : stripRight;
|
||||
|
||||
string line = this.readln.stripRight("\r\n");
|
||||
return formattedRead(line, format, data);
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
static import std.file;
|
||||
|
||||
auto deleteme = testFilename();
|
||||
std.file.write(deleteme, "hello\nworld\ntrue\nfalse\n");
|
||||
scope(exit) std.file.remove(deleteme);
|
||||
string s;
|
||||
auto f = File(deleteme);
|
||||
f.readfln!"%s"(s);
|
||||
assert(s == "hello", "["~s~"]");
|
||||
f.readfln("%s", s);
|
||||
assert(s == "world", "["~s~"]");
|
||||
|
||||
bool b1, b2;
|
||||
f.readfln("%s", b1);
|
||||
f.readfln("%s", b2);
|
||||
assert(b1 == true && b2 == false);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a temporary file by calling $(CSTDIO tmpfile).
|
||||
Note that the created file has no $(LREF name).*/
|
||||
|
@ -4489,6 +4569,70 @@ if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Reads a line from `stdin` and parses it using $(REF formattedRead, std,format,read).
|
||||
|
||||
Params:
|
||||
format = The $(MREF_ALTTEXT format string, std,format). When passed as a
|
||||
compile-time argument, the string will be statically checked against the
|
||||
argument types passed.
|
||||
data = Items to be read.
|
||||
|
||||
Returns: Same as `formattedRead`: the number of variables filled. If the
|
||||
input ends early, this number will be less that the number of variables
|
||||
provided.
|
||||
|
||||
Example:
|
||||
---
|
||||
// sum_rows.d
|
||||
void main()
|
||||
{
|
||||
import std.stdio;
|
||||
int a, b, c;
|
||||
while (readfln("%d %d %d", a, b, c) == 3)
|
||||
{
|
||||
writeln(a + b + c);
|
||||
}
|
||||
}
|
||||
---
|
||||
$(CONSOLE
|
||||
% cat << EOF > input
|
||||
1 2 3
|
||||
4 5 6
|
||||
7 8 9
|
||||
EOF
|
||||
% rdmd sum_rows.d < input
|
||||
6
|
||||
15
|
||||
24
|
||||
)
|
||||
*/
|
||||
uint readfln(alias format, Data...)(auto ref Data data)
|
||||
{
|
||||
import std.format : checkFormatException;
|
||||
|
||||
alias e = checkFormatException!(format, Data);
|
||||
static assert(!e, e);
|
||||
return .readfln(format, data);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
uint readfln(Data...)(scope const(char)[] format, auto ref Data data)
|
||||
{
|
||||
return stdin.readfln(format, data);
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
float f;
|
||||
string s;
|
||||
char c;
|
||||
int n;
|
||||
if (false) readfln("%f %s %c %d", f, s, c, n);
|
||||
if (false) readfln!"%f %s %c %d"(f, s, c, n);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience function that forwards to `core.sys.posix.stdio.fopen`
|
||||
* (to `_wfopen` on Windows)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue