reading formatted strings: readf("%s", &stringvar)

Ali Çehreli acehreli at yahoo.com
Sun Mar 25 08:04:30 PDT 2012


On 03/25/2012 06:00 AM, Tyro[17] wrote:
 > I am trying to figure out the cause of my problem in the following post:
 >
 > http://forum.dlang.org/thread/qfbugjkrerfboqhvjttw@forum.dlang.org

Sorry that I missed your question there. :(

 > and encountered something peculiar about reading strings. Whenever a
 > distinct terminator is indicated in the input format (ex. " %s@", @
 > being the terminator), readf() leaves the terminator on the input buffer
 > after reading the data. If no terminator is specified the only way to
 > indicate end of input is to use ctrl-d (ctrl-z on windows), however that
 > causes the eof indicator to be set to true and the stream is marked as
 > empty for all future attempts to access stdin.
 >
 > void main(string[] args)
 > {
 > string s1;
 > double d;
 > string s2;
 >
 > writeln("Enter a @ terminated string (multiline ok):");
 > readf(" %s@", &s1);
 > auto arr = s1.split();
 >
 > if (!stdin.eof()) {
 > writeln("The stream is not empty.");
 > } else {
 > writeln("The stream is empty.");
 > }
 > writeln("Enter another string (terminated with cntrl-d|ctrl-z):");

I am not sure about the cntrl-d|ctrl-z part though. Since it terminates 
the input, the program should not be able to read any more characters.

 > readf(" %s", &s2); // No matter how many read attempts

I advise reading string by readln(). You can call chomp() to get rid of 
whitespace around it:

     while (s2.length == 0) {
         s2 = chomp(readln());
     }

This has been my understanding of the matter: [1]

<quote>
There are surprises even when reading strings from the console.

Being character arrays, strings can contain control characters like '\n' 
as well. When reading strings from the input, the control character that 
corresponds to the Enter key that is pressed at the end of console input 
becomes a part of the string as well. Further, because there is no way 
to tell readf() how many characters to read, it continues to read until 
the end of the entire input. For these reasons, readf() does not work as 
intended when reading strings:
</quote>

 > // are made after this point, none of them will work.
 > // Insert \n after %s to see difference.
 >
 > writeln("Enter a decimal value:");
 > readf(" %s", &d);
 > //readf(" %s", &d);
 > //readf(" %s", &d);
 > //readf(" %s", &d);
 > //readf(" %s", &d);
 >
 > if (!stdin.eof()) {
 > writeln("The stream is not empty.");
 > } else {
 > writeln("The stream is empty.");
 > }
 >
 > writeln("d = ", d);
 > writeln("arr = ", arr);
 > writeln("s = ", s2);
 > }
 >
 > Is there no way to indicate eof without marking the stream (buffer?) as
 > empty for all future uses after encountering cntrl-d/cntrl-z during
 > string input? I would expect to be able to terminate string input with
 > cntrl-d/cntrl-z without rendering the input stream inaccessible.
 >
 > Thanks,
 > Andrew

With the change above (and assuming that we don't end the stream), the 
rest of the reads succeed for me.

Ali

[1] http://ddili.org/ders/d.en/strings.html



More information about the Digitalmars-d mailing list