Perl - How to output all on one line - perl

I'm new to PERL but have picked it up rather quickly as I work in C.
My question seems simple, but for the life of me I cant find a simple answer. Basically I want to print something on the same line as user input
Example
print "Please Enter Here: ";
my $input = <STDIN>;
chomp $input;
print " - You Entered: $input";
Output
Please Enter Here: 123
- You Entered: 123
This is undesired as I want all of this on one line in the terminal window. At the moment it prints the second string on the line below once the user has pressed the enter key. I guess what i'm going to need to do is something with STDIN like ignore the carriage return or newline but I'm not sure.
Desired Output
Please Enter Here: 123 - You Entered: 123
I don't know why this seems to be a complicated thing to google but I just haven't fathomed it, so any help would be appreciated.
Ta

Well, this is interesting...
First, you'd have to turn off terminal echoing, using something like IO::Stty. Once you do that, you could use getc. Note that the getc perldoc page has a sample program that could be used. You can loop until you get a \n character as input.
You can also try Term::ReadKey.
I have never done this myself. I'll have to give it a try, and if I succeed, I'll post the answer.
The Program
Ended up I already had Term::ReadKey installed:
#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
use Term::ReadKey;
ReadMode 5; # Super Raw mode
my $string;
print "Please Enter Here: ";
while ( my $char = getc ) {
last if ord( $char ) < 32; # \r? \n? \l?
$string .= $char;
print "$char";
}
ReadMode 0;
say qq( - You entered "$string".);
I realized that, depending how the terminal is setup, it's hard to know exactly what is returned when you press <RETURN>. Therefore, I punted and look for any ASCII character that's before a space.
One more thing: I didn't handle what happens if the user hit a backspace, or other special characters. Instead, I simply punt which may not be what you want to do.

In the end I did:
"\033[1A\033[45C
It uses the code functions for line up and 45 indent and it works. Thanks for all the help though.

Related

Print Line By Line

I've been trying to work on a lyrical bot for my server, but before I started to work on it, I wanted to give it a test so I came up with this script using the Lyrics::Fetcher module.
use strict;
use warnings;
use Lyrics::Fetcher;
my ($artist, $song) = ('Coldplay', 'Adventures Of A Lifetime');
my $lyrics = Lyrics::Fetcher->fetch($artist, $song, [qw(LyricWiki AstraWeb)]);
my #lines = split("\n\r", $lyrics);
foreach my $line (#lines) {
sleep(10);
print $line;
}
This script works fine, it grabs the lyrics and prints it out in a whole(which is not what I'm looking for).
I was hoping to achieve a line by line print of the lyrics every 10 seconds. Help please?
Your call to split looks suspicious. In particular the regex "\n\r". Note, the first argument to split is always interpreted as a regex regardless of whether you supply a quoted string.
On Unix systems the line ending is typically "\n". On DOS/Windows it's "\r\n" (the reverse of what you have). On ancient Macs it was "\r". To match all thre you could do:
my #lines = split(/\r\n|\n|\r/, $lyrics);
You will need to enable autoflush, otherwise the lines will just be buffered and printed when the buffer is full or when the program terminates
STDOUT->autoflush;
You can use the regex generic newline pattern \R to split on any line ending, whether your data contains CR, LF, or CR LF. This feature is available only in Perl v5.10 or better
my #lines = split /\R/, $lyrics;
And you will need to print a newline after each line of lyrics, because the split will have removed them
print $line, "\n";

Clarification on chomp

I'm on break from classes right now and decided to spend my time learning Perl. I'm working with Beginning Perl (http://www.perl.org/books/beginning-perl/) and I'm finishing up the exercises at the end of chapter three.
One of the exercises asked that I "Store your important phone numbers in a hash. Write a program to look up numbers by the person's name."
Anyway, I had come up with this:
#!/usr/bin/perl
use warnings;
use strict;
my %name_number=
(
Me => "XXX XXX XXXX",
Home => "YYY YYY YYYY",
Emergency => "ZZZ ZZZ ZZZZ",
Lookup => "411"
);
print "Enter the name of who you want to call (Me, Home, Emergency, Lookup)", "\n";
my $input = <STDIN>;
print "$input can be reached at $name_number{$input}\n";
And it just wouldn't work. I kept getting this error message:
Use of uninitialized value in concatenation (.) or string at hello.plx
line 17, line 1
I tried playing around with the code some more but each "solution" looked more complex than the "solution" that came before it. Finally, I decided to check the answers.
The only difference between my code and the answer was the presence of chomp ($input); after <STDIN>;.
Now, the author has used chomp in previous example but he didn't really cover what chomp was doing. So, I found this answer on www.perlmeme.org:
The chomp() function will remove (usually) any newline character from
the end of a string. The reason we say usually is that it actually
removes any character that matches the current value of $/ (the input
record separator), and $/ defaults to a newline..
Anyway, my questions are:
What newlines are getting removed? Does Perl automatically append a "\n" to the input from <STDIN>? I'm just a little unclear because when I read "it actually removes any character that matches the current value of $/", I can't help but think "I don't remember putting a $/ anywhere in my code."
I'd like to develop best practices as soon as possible - is it best to always include chomp after <STDIN> or are there scenarios where it's unnecessary?
<STDIN> reads to the end of the input string, which contains a newline if you press return to enter it, which you probably do.
chomp removes the newline at the end of a string. $/ is a variable (as you found, defaulting to newline) that you probably don't have to worry about; it just tells perl what the 'input record separator' is, which I'm assuming means it defines how far <FILEHANDLE> reads. You can pretty much forget about it for now, it seems like an advanced topic. Just pretend chomp chomps off a trailing newline. Honestly, I've never even heard of $/ before.
As for your other question, it is generally cleaner to always chomp variables and add newlines as needed later, because you don't always know if a variable has a newline or not; by always chomping variables you always get the same behavior. There are scenarios where it is unnecessary, but if you're not sure it can't hurt to chomp it.
Hope this helps!
OK, as of 1), perl doesn't add any \n at input. It is you that hit Enter when finished entering the number. If you don't specify $/, a default of \n will be put (under UNIX, at least).
As of 2), chomp will be needed whenever input comes from the user, or whenever you want to remove the line ending character (reading from a file, for example).
Finally, the error you're getting may be from perl not understanding your variable within the double quotes of the last print, because it does have a _ character. Try to write the string as follows:
print "$input can be reached at ${name_number{$input}}\n";
(note the {} around the last variable).
<STDIN> is a short-cut notation for readline( *STDIN );. What readline() does is reads the file handle until it encounters the contents of $/ (aka $INPUT_RECORD_SEPARATOR) and returns everything it has read including the contents of $/. What chomp() does is remove the last occurrence contents of $/, if present.
The contents is often called a newline character but it may be composed of more than one character. On Linux, it contains a LF character but on Windows, it contains CR-LF.
See:
perldoc -f readline
perldoc -f chomp
perldoc perlvar and search for /\$INPUT_RECORD_SEPARATOR/
I think best practice here is to write:
chomp(my $input = <STDIN>);
Here is quick example how chomp function ($/ meaning is explained there) works removing just one trailing new line (if any):
chomp (my $input = "Me\n"); # OK
chomp ($input = "Me"); # OK (nothing done)
chomp ($input = "Me\n\n"); # $input now is "Me\n";
chomp ($input); # finally "Me"
print "$input can be reached at $name_number{$input}\n";
BTW: That's funny thing is that I am learning Perl too and I reached hashes five minutes ago.
Though it may be obvious, it's still worth mentioning why the chomp is needed here.
The hash created contains 4 lookup keys: "Me", "Home", "Emergency" and "Lookup"
When $input is specified from <STDIN>, it'll contain "Me\n", "Me\r\n" or some other line-ending variant depending on what operating system is being used.
The uninitialized value error comes about because the "Me\n" key does not exist in the hash. And this is why the chomp is needed:
my $input = <STDIN>; # "Me\n" --> Key DNE, $name_number{$input} not defined
chomp $input; # "Me" --> Key exists, $name_number{$input} defined

Is it possible to clear the terminal with Term::ReadKey?

Is there a way to do this with the Term::ReadKey-module?
#!/usr/bin/env perl
use warnings;
use 5.012;
use Term::Screen;
say( "Hello!\n" x 5 );
sleep 2;
my $scr = Term::Screen->new();
$scr->clrscr();
I don't know why Term::ReadKey would provide such a feature or if it does. But, how about:
#!/usr/bin/env perl
use strict; use warnings;
*clrscr = $^O eq 'MSWin32'
? sub { system('cls') }
: sub { system('clear') };
print "Hello\n" for 1 .. 5;
sleep 2;
clrscr();
Not sure why you want to use Term::Readkey for clearing the screen. It definitely does not have that capability. Are you trying to use something that's part of the standard Perl installation? You can use Term::Caps which is part of the standard Perl installation. Unfortunately, it requires the Termcaps file to be on the system, and Windows doesn't have that.
use Term::Cap;
#
# Use eval to catch the error when TERM isn't defined or their is no
# Termcap file on the system.
#
my $terminal;
eval {$terminal = Term::Cap->Tgetent();};
#
# Use 'cl' to get the Screen Clearing sequence
#
if ($#) { #Most likely a Windows Terminal
system('cls'); #We really should be doing the 2 line below
# my $clear = "\e[2J"; #But, it doesn't seem to work.
# print "$clear"; #Curse You! I'll get you yet Bill Gates!
} else { #A Real Computer
my $clear = $terminal->Tputs('cl');
print "$clear";
}
print "All nice and squeeky clean!\n";
I tried printing the ANSI Escape sequence if it was a Windows Terminal, but it doesn't seem to work.
I hate doing system calls because there is a security risk . What if someone changed the cls command on you?
Term::Readkey does not provide this function directly, but usually the key combination to clear the screen in a Terminal is ^L (Control-L):
Binary
Oct
Dec
Hex
Asc
Sym
Text
00001100
14
12
c
ff
^L
Form Feed (Next Page)
So, if you want to build this in to your application using that module, you can do something like this:
use Term::ReadKey;
# Perform a normal read using getc
my $key = ReadKey( 0 );
# If ^L was pressed, clear the screen
if ( ord $key == 12 ) { print "\e[2J" }
The above example uses the raw escape sequence \e[2J which clears the entire screen. You also have the following alternatives:
Sequence
Function
\e[J
Clears from cursor until end of screen
\e[0J
Clears from cursor until end of screen
\e[1J
Clears from cursor to beginning of screen
\e[2J
Clears entire screen
\e[K
Clears from cursor to end of line
\e[0K
Clears from cursor to end of line
\e[1K
Clears from cursor to start of line
\e[2K
Clears entire line
The escape code \e refers to ASCII character number 27:
Binary
Oct
Dec
Hex
Asc
Sym
Text
00011011
33
27
1b
esc
^[
Escape
See VT100 Escape Sequences for more information.
This should even work if you're using Windows, since apparently this works there nowadays.

Why does STDIN cause my Perl program to freeze?

I am learning Perl and wrote this script to practice using STDIN. When I run the script, it only shows the first print statement on the console. No matter what I type in, including new lines, the console doesn't show the next print statement. (I'm using ActivePerl on a Windows machine.) It looks like this:
$perl script.pl
What is the exchange rate? 90.45
[Cursor stays here]
This is my script:
#!/user/bin/perl
use warnings; use strict;
print "What is the exchange rate? ";
my #exchangeRate = <STDIN>;
chomp(#exchangeRate);
print "What is the value you would like to convert? ";
chomp(my #otherCurrency = <STDIN>);
my #result = #otherCurrency / #exchangeRate;
print "The result is #{result}.\n";
One potential solution I noticed while researching my problem is that I could include use IO::Handle; and flush STDIN; flush STDOUT; in my script. These lines did not solve my problem, though.
What should I do to have STDIN behave normally? If this is normal behavior, what am I missing?
When you do
my #answer = <STDIN>;
...Perl waits for the EOF character (on Unix and Unix-like it's Ctrl-D). Then, each line you input (separated by linefeeds) go into the list.
If you instead do:
my $answer = <STDIN>;
...Perl waits for a linefeed, then puts the string you entered into $answer.
I found my problem. I was using the wrong type of variable. Instead of writing:
my #exchangeRate = <STDIN>;
I should have used:
my $exchangeRate = <STDIN>;
with a $ instead of a #.
To end multiline input, you can use Control-D on Unix or Control-Z on Windows.
However, you probably just wanted a single line of input, so you should have used a scalar like other people mentioned. Learning Perl walks you through this sort of stuff.
You could try and enable autoflush.
Either
use IO::Handle;
STDOUT->autoflush(1);
or
$| = 1;
That's why you are not seeing the output printed.
Also, you need to change from arrays '#' to scalar variables '$'
$val = <STDIN>;
chomp($val);

Why am I having trouble comparing lines from input in Perl?

I don't know what I could be doing wrong with this simple transaction, but it's not working:
print "OK? (y or n)\n";
$ans = <>;
print "\n";
if($ans eq "y"){print $ans;}
I basically want to know how to test the user input. This little bit of code won't work for me. I'm just trying to print $ans if y is entered by the user.
Any suggestions?
EDIT: - I have also tried single quotes
You're doing a couple things wrong.
(1) Don't use the diamond operator (<>) when you want <STDIN>. The diamond operator will also read files from #ARGV, which you probably don't want.
(2) $ans will never be equal to "y" unless you chomp it first. It will have a newline at the end.
A cure-all for variables of mysterious content:
use Data::Dumper;
$Data::Dumper::Useqq = 1; # show newlines, tabs, etc in visible form
$Data::Dumper::Terse = 1;
print '$ans is really: ', Dumper($ans);
Although your direct question has been answered, you may want to look at alternatives like Term::Readline
Have you tried:
if($ans eq 'y'){print $ans;}
?