www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - readf with strings

reply GreatEmerald <pastas4 gmail.com> writes:
This should be a very elementary question. How do you get a string off stdin?
Or an integer, or a boolean, for that matter? If I use this:

  float MyFloat;
  string MyString;
  readf("%f", &MyFloat);
  writeln(MyFloat);
  readf("%s", &MyString);
  writeln(MyString);

I get the float printed correctly, but when it asks to input the string,
whatever I input gets ignored - I can't reach the writeln part in any way and
I have to forcibly close the program. The same thing is with ints - if I enter
an int, it acts as if I didn't enter anything at all. But floats work fine for
some reason. Any thoughts about what is happening there?

I'm using openSUSE 11.4 and DMD 2.053.
Jun 22 2011
next sibling parent reply Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Wed, 22 Jun 2011 14:57:57 +0000, GreatEmerald wrote:

 This should be a very elementary question. How do you get a string off
 stdin? Or an integer, or a boolean, for that matter? If I use this:
 
   float MyFloat;
   string MyString;
   readf("%f", &MyFloat);
   writeln(MyFloat);
   readf("%s", &MyString);
   writeln(MyString);
 
 I get the float printed correctly, but when it asks to input the string,
 whatever I input gets ignored - I can't reach the writeln part in any
 way and I have to forcibly close the program. The same thing is with
 ints - if I enter an int, it acts as if I didn't enter anything at all.
 But floats work fine for some reason. Any thoughts about what is
 happening there?
 
 I'm using openSUSE 11.4 and DMD 2.053.

Reading from an input stream is sometimes confusing. Things to remember: - Use %s for any type unless there is reason not to - The line terminator from the previous entry is still in the input. (You may call readf(" ") to flush those white space characters. (I've just discovered this.)) - string can hold any character including space and the line terminator. That's why pressing the Enter doesn't terminate reading a string. - Use a space character before any format specifier to ignore zero or more whitespace characters before the previous input: " %s". - To read a string (actually a line), use chomp(readln()) - I don't know whether this is intended and I don't think that we should routinely use this: The EOF (Ctrl-D on Unix consoles, Ctrl-Z on Windows) terminates reading the string but strangely not the entire input. import std.stdio; import std.string; void main() { float MyFloat; readf(" %s", &MyFloat); writeln(MyFloat); readf(" "); string MyString = chomp(readln()); writeln(MyString); } Ali
Jun 22 2011
next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Wed, 22 Jun 2011 20:59:46 +0300, Dainius (GreatEmerald) wrote:

 I see. Using %s does indeed work with ints, and chomp(readln()) works
 with strings. It's rather counter-intuitive, though.

There are many counter intuitive bits and imperfect modelling in stream I/ O. For example "42a" is perfectly fine when reading an int because the reader decides that the '4' and '2' characters make up the int and 'a' must be for something else. Why? :) What if I really meant that "42a" should be read as int. It should be an error! I think strings are special because they are powerful to take any character. Additionally output and input are not symmetrical: The ints 1 and 2 would be written as 12 back to back but they can't be read as two ints.
 I wonder why there
 isn't a simpler way to do this, something like writeln() - you could
 input the variables as parameters and it would automatically read
 them...

I know that the insistence on the space character to munch white space is intentional. Andrei commented on a bug that this is more consistent than scanf()'s implicit munching. There is <cstream> that is being (is?) deprecated. It reads simpler like writeln: import std.cstream; void main() { double d; int i; din.readf(&d, &i); dout.writefln("d: %s, i: %s", d, i); } It would still be problematic with strings. How many characters should be a part of it? Ali
Jun 22 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
This library has some nice user-input methods for D2:
https://github.com/he-the-great/JPDLibs/tree/cmdln
Jun 22 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Ali «ehreli:

 "oku" means "read":
 
     // Read into an existing variable
     double d;
     oku("Please enter a double: ", &d);
 
     // Read and return a value
     int i = oku!int("Please enter an int: ");

I have a related enhancement request since lot of time: http://d.puremagic.com/issues/show_bug.cgi?id=4716 Bye, bearophile
Jun 22 2011
parent Kai Meyer <kai unixlords.com> writes:
On 06/23/2011 02:27 AM, Dainius (GreatEmerald) wrote:
 I have a related enhancement request since lot of time:
 http://d.puremagic.com/issues/show_bug.cgi?id=4716

 Bye,
 bearophile

That's exactly what I'd like to see. Voted. After all, D is created with practicality in mind, and doing all that parsing is the opposite of what it's trying to achieve.

The goal here is to have semantics for "Read an int from STDIN." I think the difficulty here is this really *should* be "Read a T from a stream." In C++, we have the stream operators ">>" and "<<". I really really really really miss these. I would love to have my stream operators back (and then implement the operators for classes and structs.) I think that "a = stdin.type_read!int();" or "std.type_read!int(&a);" would go a long way in getting there, as long as we could extend the template. I don't like the way python takes input from STDIN with raw_input() and input(). I'm not opposed to having a language support those semantics, but I would rather have a generic stream reader that does the conversion to a type for me that allows me to extend the conversion to include my own types.
Jun 23 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Wed, 22 Jun 2011 20:17:39 +0200, Andrej Mitrovic wrote:

 This library has some nice user-input methods for D2:
 https://github.com/he-the-great/JPDLibs/tree/cmdln

Thanks! :) The Turkish D community has experimented with a similar solution: http://ddili.org/forum/post/2960 "oku" means "read": // Read into an existing variable double d; oku("Please enter a double: ", &d); // Read and return a value int i = oku!int("Please enter an int: "); Ali
Jun 22 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I didn't know there was a Turkish D community. :)
Jun 22 2011
prev sibling next sibling parent Jimmy Cao <jcao219 gmail.com> writes:
--0016361e7e322710ea04a6516240
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

On Wed, Jun 22, 2011 at 1:31 PM, Ali =C7ehreli <acehreli yahoo.com> wrote:

 On Wed, 22 Jun 2011 20:17:39 +0200, Andrej Mitrovic wrote:

 This library has some nice user-input methods for D2:
 https://github.com/he-the-great/JPDLibs/tree/cmdln

Thanks! :) The Turkish D community has experimented with a similar solution: http://ddili.org/forum/post/2960 "oku" means "read": // Read into an existing variable double d; oku("Please enter a double: ", &d); // Read and return a value int i =3D oku!int("Please enter an int: "); Ali

The design of this community site is quite splendid. So D has three major language sub-communities: German, Japanese, and Turkish? --0016361e7e322710ea04a6516240 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Wed, Jun 22, 2011 at 1:31 PM, Ali =C7ehreli <span dir=3D"ltr">&lt;<a hre= f=3D"mailto:acehreli yahoo.com">acehreli yahoo.com</a>&gt;</span> wrote:<br=
<div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"marg=

<div class=3D"im">On Wed, 22 Jun 2011 20:17:39 +0200, Andrej Mitrovic wrote= :<br> <br> &gt; This library has some nice user-input methods for D2:<br> &gt; <a href=3D"https://github.com/he-the-great/JPDLibs/tree/cmdln" target= =3D"_blank">https://github.com/he-the-great/JPDLibs/tree/cmdln</a><br> <br> </div>Thanks! :)<br> <br> The Turkish D community has experimented with a similar solution:<br> <br> =A0<a href=3D"http://ddili.org/forum/post/2960" target=3D"_blank">http://d= dili.org/forum/post/2960</a><br> <br> &quot;oku&quot; means &quot;read&quot;:<br> <br> =A0 =A0// Read into an existing variable<br> =A0 =A0double d;<br> =A0 =A0oku(&quot;Please enter a double: &quot;, &amp;d);<br> <br> =A0 =A0// Read and return a value<br> =A0 =A0int i =3D oku!int(&quot;Please enter an int: &quot;);<br> <font color=3D"#888888"><br> Ali<br> </font></blockquote></div><br><div>The design of this community site is qui= te splendid. =A0So D has three major language sub-communities: =A0German, J= apanese, and Turkish?</div> --0016361e7e322710ea04a6516240--
Jun 22 2011
prev sibling next sibling parent Ali =?iso-8859-1?q?=C7ehreli?= <acehreli yahoo.com> writes:
On Wed, 22 Jun 2011 13:45:56 -0500, Jimmy Cao wrote:

 On Wed, Jun 22, 2011 at 1:31 PM, Ali Çehreli <acehreli yahoo.com> wrote:
 
 On Wed, 22 Jun 2011 20:17:39 +0200, Andrej Mitrovic wrote:

 This library has some nice user-input methods for D2:
 https://github.com/he-the-great/JPDLibs/tree/cmdln

Thanks! :) The Turkish D community has experimented with a similar solution: http://ddili.org/forum/post/2960


 The design of this community site is quite splendid.

Thank you! :) We have three books too: - D Programming Language (complete, except special memory management like emplace(), the 'new' and 'delete' operators, interacting with the garbage collector, etc. That chapter is being written as we speak) - GtkD (needs work) - Game Programming with SDL (freshly started; moving on pretty well) http://ddili.org/ders/index.html
 So D has three
 major language sub-communities:  German, Japanese, and Turkish?

The wiki lists others: http://www.prowiki.org/wiki4d/wiki.cgi Ali
Jun 22 2011
prev sibling next sibling parent Kai Meyer <kai unixlords.com> writes:
On 06/22/2011 09:30 AM, Ali Çehreli wrote:
 On Wed, 22 Jun 2011 14:57:57 +0000, GreatEmerald wrote:

 This should be a very elementary question. How do you get a string off
 stdin? Or an integer, or a boolean, for that matter? If I use this:

    float MyFloat;
    string MyString;
    readf("%f",&MyFloat);
    writeln(MyFloat);
    readf("%s",&MyString);
    writeln(MyString);

 I get the float printed correctly, but when it asks to input the string,
 whatever I input gets ignored - I can't reach the writeln part in any
 way and I have to forcibly close the program. The same thing is with
 ints - if I enter an int, it acts as if I didn't enter anything at all.
 But floats work fine for some reason. Any thoughts about what is
 happening there?

 I'm using openSUSE 11.4 and DMD 2.053.

Reading from an input stream is sometimes confusing. Things to remember: - Use %s for any type unless there is reason not to - The line terminator from the previous entry is still in the input. (You may call readf(" ") to flush those white space characters. (I've just discovered this.)) - string can hold any character including space and the line terminator. That's why pressing the Enter doesn't terminate reading a string. - Use a space character before any format specifier to ignore zero or more whitespace characters before the previous input: " %s". - To read a string (actually a line), use chomp(readln()) - I don't know whether this is intended and I don't think that we should routinely use this: The EOF (Ctrl-D on Unix consoles, Ctrl-Z on Windows) terminates reading the string but strangely not the entire input. import std.stdio; import std.string; void main() { float MyFloat; readf(" %s",&MyFloat); writeln(MyFloat); readf(" "); string MyString = chomp(readln()); writeln(MyString); } Ali

Remember that readf is reading characters, and converting them to types for you. I've just gotten in the habbit of reading in the string, and then parsing the string on my own. Readf doesn't grant me anything special that I can't do on my own. It's easy enough to do something like this: [kai.meyer kai-rhel6 sandbox]$ cat d_read.d import std.stdio; import std.string; import std.conv; void main() { string[] buffer; int a; float b; string c; buffer = chomp(readln()).split(" "); a = to!(int)(buffer[0]); b = to!(float)(buffer[1]); c = buffer[2..$].join(" "); writef("Read in: '%d' '%f' '%s'\n", a, b, c); } If I type: 1 1.3 this is a string On the command line after the execution, I get this back: Read in: '1' '1.300000' 'this is a string' It's not very stream-ish, because readln breaks on a new line. You could call the "buffer = chomp..." line again if (buffer.length == 0) before you attempt another conversion.
Jun 22 2011
prev sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
 I have a related enhancement request since lot of time:
 http://d.puremagic.com/issues/show_bug.cgi?id=4716

 Bye,
 bearophile

That's exactly what I'd like to see. Voted. After all, D is created with practicality in mind, and doing all that parsing is the opposite of what it's trying to achieve.
Jun 23 2011
prev sibling parent "Dainius (GreatEmerald)" <pastas4 gmail.com> writes:
I see. Using %s does indeed work with ints, and chomp(readln()) works
with strings. It's rather counter-intuitive, though.
I wonder why there isn't a simpler way to do this, something like
writeln() - you could input the variables as parameters and it would
automatically read them...
Jun 22 2011