How do I print the '%' character with 'printf'? - perl

Simple problem that I can't figure out...
How can I print a '%' character within a printf string? The code below prints it, but gives an 'invalid conversion' error as well.
printf "\t\t".$hour."00 HRS\t=>\t%.2f\t%.2f\t%.1f\%\n", $total, $max15, ($max15/$total*100);
Should output something like:
0000 HRS => 3125.19 898.02 28.7%

You would use %%, not \% (from man printf)

Instead of \% use %% :)

%% for a single %

On hindsight, there was a crude alternative which would have done the same thing.
Print the '%' symbol as a string:
printf "\t\t".$hour."00 HRS\t=>\t%.2f\t%.2f\t%.1f%s\n", $total, $max15, ($max15/$total*100), "%";

Use %% to print a single %
printf "\t\t".$hour."00 HRS\t=>\t%.2f\t%.2f\t%.1f%%\n", $total, $max15, ($max15/$total*100);

This is a bit tricky because the documentation for the template for printf is actually in the documentation for sprintf. You have to catch that line in the middle of the paragraph to know to look there.

Related

Ip to hexa formatting

i need to convert decimal ip to hexa value.
example:110.1.1.3 to 6e01:103.
But by using below code i am getting it in 6e01103. I need it either 6e01:103 or 6e:01:103 format. And then need to concatenate with hexa value 64:ff9b::, my end output needd to be 64:ff9b::6e01:103. Kindly help me in this.
sub ip_hexa($){
my $ip = shift;
my #octets = split /\./, $ip;
my $result;
foreach (#octets){
$hexa_ip = join":",printf("%02x", "$_");
}
return $hexa_ip;
}
I'm not completely certain about the output you want, but there are a few issues with the code which I'll list below:
The $ in the function declaration is not required. It sets the function's prototype which most likely does not do what you think it does. See perlsub for details.
$hexa_ip should be declared before being used as good practice to prevent hard to find errors. Perhaps you meant my $hexa_ip instead of my $result? In any case, use use strict at the start of the program to catch such errors.
printf() prints to screen and only returns a boolean. Look at sprintf for the right function to use.
join() is not being used correctly. See join.
# 6e01:103
sprintf "%x:%x",
unpack 'nn',
pack 'C4',
split /\./,
'110.1.1.3'
# 6e:01:103
sprintf "%x:%x:%x",
unpack 'CCn',
pack 'C4',
split /\./,
'110.1.1.3'
The sprintf lines can be replaced with join ':', map sprintf '%x',

How can I replace a particular character with its upper-case counterpart?

Consider the following string
String = "this is for test. i'm new to perl! Please help. can u help? i hope so."
In the above string after . or ? or ! the next character should be in upper case. how can I do that?
I'm reading from text file line by line and I need to write modified data to another file.
your help will be greatly appreciated.
you could use a regular expression
try this:
my $s = "...";
$s =~ s/([\.\?!]\s*[a-z])/uc($1)/ge; # of course $1 , thanks to plusplus
the g-flag searches for all matches and the e-flag executes uc to convert the letter to uppercase
Explanation:
with [.\?!] you search for your punctuation marks
\s* is for whitespaces between the marks and the first letter of your next word and
[a-z] matches on a single letter (in this case the first one of the next word
the regular expression mentioned above searches with these patterns for every appearance of a punctuation mark followed by (optional) whitespaces and a letter and replaces it with the result of uc (which converts the match to uppercase).
For example:
my $s = "this is for test. i'm new to perl! Please help. can u help? i hope so.";
$s =~ s/([\.\?!]\s*[a-z])/uc(&1)/ge;
print $s;
will find ". i", "! P", ". c" and "? i" and replaces then, so the printed result is:
this is for test. I'm new to perl! Please help. Can u help? I hope so.
You can use the substitution operator s///:
$string =~ s/([.?!]\s*\S)/ uc($1) /ge;
Here's a split solution:
$str = "this is for test. im new to perl! Please help. can u help? i hope so.";
say join "", map ucfirst, split /([?!.]\s*)/, $str;
If all you are doing is printing to a new file, you don't need to join the string back up. E.g.
while ($line = <$input>) {
print $output map ucfirst, split /([?!.]\s*)/, $line;
}
edit - completely misread the question, thought you were just asking to uppercase the is for some reason, apologies for any confusion!
as the answers so far state, you could look at regular expressions, and the substitution operator (s///). No-one has mentioned the \b (word boundary) character though, which may be useful to find the single is - otherwise you are going to have to keep adding punctuation characters that you find to the character class match (the [ ... ]).
e.g.
my $x = "this is for test. i'm new to perl! Please help. can u help? i hope so. ".
\"i want it to work!\". Dave, Bob, Henry viii and i are friends. foo i bar.";
$x =~ s/\bi\b/I/g; # or could use the capture () and uc($1) in eugene's answer
gives:
# this is for test. I'm new to perl! Please help. can u help? I hope so.
# "I want it to work!". Dave, Bob, Henry viii and I are friends. foo I bar.

Matlab: Remove chars from string with unicode chars

I have a long string that looks like:
その他,-9999.00
その他,-9999.00
その他,-9999.00
その他,-9999.00
and so forth. I'd like to split at linebreak and remove everything up to a comma, and just keep the floats. So my output should be something like:
A =
[-9999.99 -9999.99 -9999.99 -9999.99]
Any idea how to do that relatively quickly (a few seconds at most)? There are close to a million lines in that string.
Thanks!
I think the best way to do this is with textscan:
out = textscan(str, '%*s%f', 'delimiter', ',');
out = out{1};
I'm assuming the input is in a file. And I'm also assuming that the file is UTF-8 encoded, otherwise this won't work.
My solution is a simple Perl script. No doubt it can be done with MATLAB, but different tools have different strengths. I wouldn't attempt numerical analysis with Perl, that's for sure.
convert.pl
print "A = \n [ ";
while (<>) {
chomp;
s/.*,//;
print " ";
print;
}
print " ]";
input.txt
その他,-9999.00
その他,-9999.00
その他,-9999.00
その他,-9999.00
Command line
perl convert.pl < input.txt > output.txt
output.txt
A =
[ -9999.00 -9999.00 -9999.00 -9999.00 ]
Partial answer since I don't have access to matlab from home
The following can be used to split on tab. Use this to split on newline.
s=sprintf('one\ttwo three\tfour');
r=regexp(s,'\t','split')
% r = 'one' 'two three' 'four'
help strtok might be helpful as well
Here's how to use regexp with Matlab for your problem (with str containing your string):
out = regexp(str,[',([^,',char(10),']+)',char(10)],'tokens')
out = cat(1,out{:});
str2double(out)
out =
-9999
-9999
-9999
-9999
One simple way to extract the numeric parts and convert them to doubles is to use the functions ISMEMBER and STR2NUM:
A = str2num(str(ismember(str,',.e-0123456789')));

Perl: basic question, function functionality

What does this function do?
sub MyDigit {
return <<END;
0030\t0039
END
}
That's called a "here-document", and is used for breaking strings up over multiple lines as an alternative to concatenation or list operations:
print "this is ",
"one line when printed, ",
"because print takes multiple ",
"arguments and prints them all!\n";
print "however, you can also " .
"concatenate strings together " .
"and print them all as one string.\n";
print <<DOC;
But if you have a lot of text to print,
you can use a "here document" and create
a literal string that runs until the
delimiter that was declared with <<.
DOC
print "..and now we're back to regular code.\n";
You can read more about here-documents in the manual: see perldoc perlop.
You’ve all missed the point!
It’s defining a user-defined property for use in \p{MyDigit} and \P{MyDigit} using regular expressions.
It’s like these:
sub InKana {
return <<'END';
3040 309F
30A0 30FF
END
}
Alternatively, you could define it in terms of existing property names:
sub InKana {
return <<'END';
+utf8::InHiragana
+utf8::InKatakana
END
}
You can also do set subtraction using a "C<->" prefix. Suppose you only
wanted the actual characters, not just the block ranges of characters.
You could weed out all the undefined ones like this:
sub IsKana {
return <<'END';
+utf8::InHiragana
+utf8::InKatakana
-utf8::IsCn
END
}
You can also start with a complemented character set using the "C" prefix:
sub IsNotKana {
return <<'END';
!utf8::InHiragana
-utf8::InKatakana
+utf8::IsCn
END
}
I figure I must be right, since I’m speaking ex camelis. :)
It uses something called a Here Document to return a string "0030\t0039"
It returns the string "0030\t0039\n" (\t being a tab and \n a newline that is being added because the line ends in a newline (obviously)).
<<FOO
sometext
FOO
Is a so-called heredoc, a way to conveniently write multi-line strings (though here it is used with only one line).
You can help yourself by trying a simple experiment:
C:\Temp> cat t.pl
#!/usr/bin/perl
use strict; use warnings;
print MyDigit();
sub MyDigit {
return <<END;
0030\t0039
END
}
Output:
C:\Temp> t | xxd
0000000: 2020 2020 3030 3330 0930 3033 390d 0a 0030.0039..
Now, in your case, the END is not lined up at the beginning of the line, so you should have gotten the message:
Can't find string terminator "END" anywhere before EOF at …

What should I use instead of printf in Perl?

I need to use some string replacement in Perl to ease translations, i.e. replace many
print "Outputting " . $n . " numbers";
by something like
printf ("Outputting %d numbers", $n);
However, I'd like to replace printf with something easier to parse for humans, like this:
printX ("Outputting {num} numbers", { num => $n });
or generally something more Perly.
Can you recommend something (from CPAN or not) you like and use?
What about simply:
print "Outputting $n numbers";
That's very Perly. If you don't need any kind of fancy formatting, string interpolation is definitely the way to go.
Most Templating modules on CPAN will probably do what you want. Here's an example using Template Toolkit...
use Template;
my $tt = Template->new;
$tt->process( \"Outputting [% num %] numbers\n", { num => 100 } );
And you can mimic your required example with something like this...
sub printX {
use Template;
my $tt = Template->new( START_TAG => '{', END_TAG => '}' );
$tt->process( \( $_[0] . "\n" ), $_[1] );
}
and you've got...
printX 'Outputting {num} numbers' => { num => 100 };
The print builtin is very convenient for most situations. Besides variable interpolation:
print "Outputting $n numbers"; # These two lines
print "Outputting ${n} numbers"; # are equivalent
Remember that print can take multiple arguments, so there is no need to concatenate them first into a single string if you need to print the result of a subroutine call:
print "Output data: ", Dumper($data);
However, for outputting numbers other than simple integers, you'll probably want the formatting convenience of printf. Outputting other data types is easy with print, though.
You can use join to conveniently output arrays:
print join ', ', #array;
And combine with map and keys to output hashes:
print join ', ', map {"$_ : $hash{$_}"} keys %hash;
Use the qq operator if you want to output quotes around the data:
print join ', ', map {qq("$_" : "$hash{$_}"}) keys %hash;
If you're looking to ease translations you should consider using one of the L10n/i18n CPAN modules that are available. Specifically, a good overview of why your approach will end up falling short is written up as part of the Local::Maketext docs.
Another great module that pairs nicely with Locale::Maketext is Locale::Maketext::Lexicon. This allows you to use more standard localization formats such as gettext's .po/.mo files which have GUI tools to help translators work through all the text that needs translating. Locale::Maketext::Lexicon also comes with a helper script (xgettext.pl) that helps keep your localization files up-to-date with your templates or modules that have text that need translating. I've had very good results with this kind of setup in the past.
It seems you want to have a different way of parsing strings. I would advise you not to do this. The only one who is seeing the syntax with the %d in it is the developer and he will exactly understand what is meant. The printf syntax is powerful because of the options like padding, decimals etc.
I think you want to use more a replace method. It is perlish to do s/{num}/$n/.
In light of your comment about being for translators I suggest writing a perl script that strips all printf() and tabulates them in an easier more translator friendly manner.
Something like this:
while(<>)
{
#regex for striping printf
#print in tabulated form
}
If you print out the line number too you can easily write another program to replace the translated text.
This solution wouldn't take you any longer than re-factoring away from printf() and it's reusable.
I would definitely stick with printf(), it's standard across many languages.
It has almost become a standard for string output. Like i is for for loops.
Generally answer from Draegtun is great, but if you'd need something smaller (i.e. less memory), and not as powerful you can easily do it using this function:
sub printX {
my ( $format, $vars ) = #_;
my #sorted_keys = sort { length($b) <=> length($a) } keys %{ $vars };
my $re = join '|', map { "\Q$_\E" } #sorted_keys;
$format =~ s/ \{ \s* ($re) \s* \} /$vars->{$1}/xg;
print $format;
}
well, perl has printf function...
wait, do you want something like python's string formatting with dict?
>>> print '%(key)s' % {'key': 'value'}
value
mmm, I don't know something like that exist in perl...
at least not this "easy"...
maybe Text::Sprintf::Named can be your friend