Thread overview
Calling readln() after readf
Apr 24, 2021
PinDPlugga
Apr 24, 2021
Imperatorn
Apr 24, 2021
Ali Çehreli
6 days ago
Gary Chike
6 days ago
Ali Çehreli
5 days ago
Gary Chike
5 days ago
Gary Chike
5 days ago
Ali Çehreli
April 24, 2021

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:

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:

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?

April 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

April 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

6 days ago

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;
}

Ali

Hi 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? :

     auto catcher = readln.strip;

P.S. I love your book on D! :)

Cheers,

Gary Chike

6 days ago
On 6/19/22 15:52, Gary Chike wrote:
> 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;
>> }
>>
>> Ali
>
> Hi 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;
> ```

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.

> P.S. I love your book on D! :)

Thank you! :)

>
> Cheers,
>
> Gary Chike
>

Ali

5 days ago

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.

Ali

Thank 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?:

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

5 days ago

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. :)

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.");
	}
}
5 days ago
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 datatype

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

Ali