digitalmars.D.learn - Calling readln() after readf
- PinDPlugga (56/56) Apr 24 2021 I didn't want to necropost, but I ran into the same behaviour as
- Imperatorn (2/7) Apr 24 2021 https://dlang.org/library/std/string/chomp.html
- =?UTF-8?Q?Ali_=c3=87ehreli?= (23/28) Apr 24 2021 Just to make sure, this is a common issue for other languages as well.
- Gary Chike (12/25) Jun 19 2022 Hi Ali,
- =?UTF-8?Q?Ali_=c3=87ehreli?= (13/41) Jun 19 2022 The original program said "Please enter a number: ". If the program was
- Gary Chike (28/35) Jun 20 2022 Thank you for your input, Ali! Would it be appropriate to forego
- Gary Chike (36/36) Jun 20 2022 I should have qualified the above with: _ and I will be
- =?UTF-8?Q?Ali_=c3=87ehreli?= (5/8) Jun 20 2022 Makes sense. The following are related as well:
- Gary Chike (2/6) Jun 26 2022 Thank you so much for your input! Cheers! :)
- Gary Chike (12/21) Jul 05 2022 It's interesting from my own experimentation and observation,
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/9) Jul 05 2022 Exactly. parse takes the input by reference (necessitating an lvalue) so...
- Steven Schveighoffer (9/35) Jul 05 2022 Yes, you have 2 orthogonal desires:
- Gary Chike (2/2) Jul 06 2022 Thanks for the extra info guys! D is one of my favorite languages
I didn't want to necropost, but I ran into the same behaviour as in this post: https://forum.dlang.org/post/yfybveovbknvvxmioivd forum.dlang.org and was just curious to understand it better. If I call readln() after having previously called readf(), it does not behave as expected: ```d import std.stdio, std.string; void main() { write("Please enter a number: "); double number; readf(" %s", number); write("Please enter a string: "); string input = strip(readln()); writefln!("number: %s --- string: %s")(number, input); } ``` Gives me the following: ``` Please enter a number: 1 Please enter a string: number: 1 ---- string: ``` I know I can get this to work replacing the `strin(readln())` with `readf(" %s\n", input)`, but I also found if I just call `strip(readln())` an extra time this worked as well, but what is confusing to me is if I have multiple readf's I still only need to call readln one extra time to get it to work as expected: ```d import std.stdio, std.string; void main() { write("Please enter a number: "); double number1; readf(" %s", number1); write("Please enter a number: "); double number2; readf(" %s", number2); // Handle what should be two \n's from readf? string input = strip(readln()); // Continue as normal write("Please enter a string: "); input = strip(readln()); writefln!("number1: %s --- number2: %s --- string: %s") (number1, number2, input); } ``` And this works. ``` Please enter a number: 1 Please enter a number: 2 Please enter a string: hello number1: 1 --- number2: 2 --- string: hello ``` Could anyone help explain this to me, and also is there a better way to handle this when wanting to use a mix of readf and readln?
Apr 24 2021
On Saturday, 24 April 2021 at 14:46:06 UTC, PinDPlugga wrote:I didn't want to necropost, but I ran into the same behaviour as in this post: https://forum.dlang.org/post/yfybveovbknvvxmioivd forum.dlang.org and was just curious to understand it better. [...]https://dlang.org/library/std/string/chomp.html
Apr 24 2021
On 4/24/21 7:46 AM, PinDPlugga wrote:write("Please enter a number: "); double number; readf(" %s", number);Just to make sure, this is a common issue for other languages as well. As the explanation, the character ('\n') that you injected into stdin by pressing Enter is not (and should not be) removed by readf.write("Please enter a string: "); string input = strip(readln());Because of that '\n' character, that readln() reads an empty line. There is no way other than reading and discarding all input at stdin but luckily, readf's "formatted" behavior is able to take care of it because any character that match the format string will be read and discarded by readf: readf(" %s\n", number); As a side note, that '\n' should work on all platforms even if the terminal injects two characters. As a general solution, you can use a function like this: auto readLine(S = string)(File file = stdin) { while (!file.eof) { auto line = file.readln!S.strip; if (!line.empty) { return line; } } return null; } Ali
Apr 24 2021
On Saturday, 24 April 2021 at 22:13:45 UTC, Ali Çehreli wrote:On 4/24/21 7:46 AM, PinDPlugga wrote: ... As a general solution, you can use a function like this: auto readLine(S = string)(File file = stdin) { while (!file.eof) { auto line = file.readln!S.strip; if (!line.empty) { return line; } } return null; } AliHi Ali, Being a new D learner, I've noticed this behavior as well. Thank you for providing the 'readLine' function! Would it be considered poor coding style to intercept the stream between readf and readln with the following statement? : ```d auto catcher = readln.strip; ``` P.S. I love your book on D! :) Cheers, Gary Chike
Jun 19 2022
On 6/19/22 15:52, Gary Chike wrote:On Saturday, 24 April 2021 at 22:13:45 UTC, Ali Çehreli wrote:The original program said "Please enter a number: ". If the program was interacting with a human and the human entered a number, then the rest of the line would be understood to be ignored and your method works. On the other hand, the readLine() function would not ignore the rest of the line and use it. But I think yours makes more sense. :) But when the program interacts with piped data, there may be multiple \n characters and all of those might have to be ignored before reading the next non-empty line. So you may want to do readln.strip multiple times? I don't know. It all depends on the use case.On 4/24/21 7:46 AM, PinDPlugga wrote: ... As a general solution, you can use a function like this: auto readLine(S = string)(File file = stdin) { while (!file.eof) { auto line = file.readln!S.strip; if (!line.empty) { return line; } } return null; } AliHi Ali, Being a new D learner, I've noticed this behavior as well. Thank you for providing the 'readLine' function! Would it be considered poor coding style to intercept the stream between readf and readln with the following statement? : ```d auto catcher = readln.strip; ```P.S. I love your book on D! :)Thank you! :)Cheers, Gary ChikeAli
Jun 19 2022
On Monday, 20 June 2022 at 00:43:17 UTC, Ali Çehreli wrote:... But when the program interacts with piped data, there may be multiple \n characters and all of those might have to be ignored before reading the next non-empty line. So you may want to do readln.strip multiple times? I don't know. It all depends on the use case. AliThank you for your input, Ali! Would it be appropriate to forego `readf` and read input as a string using `readln` ,benefiting from the `strip` function, then convert to their appropriate datatype as in the following example?: ```d module hello_world; import std.stdio; import std.string; // strip() import std.conv; // to!int(),to!float() void main() { writeln("Hello world from D!"); write("What is your name? "); auto fname = readln.strip; writeln("It's so nice to meet you ", fname, "!"); write("How old are you? "); auto age = to!int(readln.strip); write("What is your GPA? "); auto gpa = to!float(readln.strip); writeln("So, ", fname, ", you are ", age, " years old and your GPA is ", gpa, ".. stellar!"); } ``` Also I signed up with Educative.io to do your interactive D language lessons. It really goes so well with your book :) Cheers, Gary Chike
Jun 20 2022
I should have qualified the above with: _ and I will be performing operations on the numeric datatype, since just outputting simply strings, as in the above example, would require nothing more than string data types. :) ```d module hello_world; import std.stdio; import std.string; // strip() import std.conv; // to!int(),to!float() void main() { writeln("Hello world from D!"); write("What is your name? "); auto fname = readln.strip; writeln("It's so nice to meet you ", fname, "!"); write("How old are you? "); auto age = to!int(readln.strip); write("What is your GPA? "); auto gpa = to!float(readln.strip); if (gpa > 4) { writeln("Sorry, 4 is the highest GPA "); gpa = 4; } writeln("So, ", fname, ", you are ", age, " years old and your GPA is ", gpa, ".. stellar!"); writeln("Can you increase your GPA? "); if(gpa == 4) { writeln("Your GPA is already as high as it can be!"); } else { gpa = gpa > 3.5 ? 4 : (gpa + 0.5); writeln("If you study hard, your GPA will likely be ", gpa); age = age + 4; writeln("But that may take 4 years, and you will be ", age, " years old by that time."); } } ```
Jun 20 2022
On 6/20/22 07:00, Gary Chike wrote:Would it be appropriate to forego `readf` and read input as a string using `readln` ,benefiting from the `strip` function, then convert to their appropriate datatypeMakes sense. The following are related as well: https://dlang.org/library/std/conv/parse.html https://dlang.org/library/std/format/read/formatted_read.html Ali
Jun 20 2022
On Monday, 20 June 2022 at 16:08:33 UTC, Ali Çehreli wrote:Makes sense. The following are related as well: https://dlang.org/library/std/conv/parse.html https://dlang.org/library/std/format/read/formatted_read.html AliThank you so much for your input! Cheers! :)
Jun 26 2022
On Monday, 20 June 2022 at 16:08:33 UTC, Ali Çehreli wrote:On 6/20/22 07:00, Gary Chike wrote:It's interesting from my own experimentation and observation, comparing `parse!int()` vs `to!int()` For instance, I can formulate a statement such as this using `to!int()`: `auto age = to!int(readln.strip());` but the same syntax using `parse!int()` would generate an error: `auto age = parse!int(readln.strip());` So, in order to use `parse!int()`, I would need to separate it into two statements with a variable acting as an intermediary: ``` auto input = readln(); auto age = parse!int(input);Would it be appropriate to forego `readf` and read input as a string using `readln` ,benefiting fromthe `strip`function, then convert to their appropriate datatypeMakes sense. The following are related as well: https://dlang.org/library/std/conv/parse.html https://dlang.org/library/std/format/read/formatted_read.html Ali
Jul 05 2022
On 7/5/22 17:14, Gary Chike wrote:So, in order to use `parse!int()`, I would need to separate it into two statements with a variable acting as an intermediary: ``` auto input = readln(); auto age = parse!int(input);Exactly. parse takes the input by reference (necessitating an lvalue) so that the input is consumed for the next step(s) of parsing. Ali
Jul 05 2022
On 7/5/22 8:14 PM, Gary Chike wrote:On Monday, 20 June 2022 at 16:08:33 UTC, Ali Çehreli wrote:Yes, you have 2 orthogonal desires: 1. I want to update the original range or not 2. I want to treat the entire range as representing my conversion type or just the first part. Phobos only handles 2 of the 4 possible scenarios. Well, really one scenario (reading the entire range, and wanting to update the original) is not important. -SteveOn 6/20/22 07:00, Gary Chike wrote:It's interesting from my own experimentation and observation, comparing `parse!int()` vs `to!int()` For instance, I can formulate a statement such as this using `to!int()`: `auto age = to!int(readln.strip());` but the same syntax using `parse!int()` would generate an error: `auto age = parse!int(readln.strip());` So, in order to use `parse!int()`, I would need to separate it into two statements with a variable acting as an intermediary: ``` auto input = readln(); auto age = parse!int(input);Would it be appropriate to forego `readf` and read input as a string using `readln` ,benefiting fromthe `strip`function, then convert to their appropriate datatypeMakes sense. The following are related as well: https://dlang.org/library/std/conv/parse.html https://dlang.org/library/std/format/read/formatted_read.html
Jul 05 2022
Thanks for the extra info guys! D is one of my favorite languages I'm currently learning. :)
Jul 06 2022