How can I convert a string to a number in Perl? - string

I have a string which holds a decimal value in it and I need to convert that string into a floating point variable. So an example of the string I have is "5.45" and I want a floating point equivalent so I can add .1 to it. I have searched around the internet, but I only see how to convert a string to an integer.

You don't need to convert it at all:
% perl -e 'print "5.45" + 0.1;'
5.55

This is a simple solution:
Example 1
my $var1 = "123abc";
print $var1 + 0;
Result
123
Example 2
my $var2 = "abc123";
print $var2 + 0;
Result
0

Perl is a context-based language. It doesn't do its work according to the data you give it. Instead, it figures out how to treat the data based on the operators you use and the context in which you use them. If you do numbers sorts of things, you get numbers:
# numeric addition with strings:
my $sum = '5.45' + '0.01'; # 5.46
If you do strings sorts of things, you get strings:
# string replication with numbers:
my $string = ( 45/2 ) x 4; # "22.522.522.522.5"
Perl mostly figures out what to do and it's mostly right. Another way of saying the same thing is that Perl cares more about the verbs than it does the nouns.
Are you trying to do something and it isn't working?

Google lead me here while searching on the same question phill asked (sorting floats) so I figured it would be worth posting the answer despite the thread being kind of old. I'm new to perl and am still getting my head wrapped around it but brian d foy's statement "Perl cares more about the verbs than it does the nouns." above really hits the nail on the head. You don't need to convert the strings to floats before applying the sort. You need to tell the sort to sort the values as numbers and not strings.
i.e.
my #foo = ('1.2', '3.4', '2.1', '4.6');
my #foo_sort = sort {$a <=> $b} #foo;
See http://perldoc.perl.org/functions/sort.html for more details on sort

As I understand it int() is not intended as a 'cast' function for designating data type it's simply being (ab)used here to define the context as an arithmetic one. I've (ab)used (0+$val) in the past to ensure that $val is treated as a number.

$var += 0
probably what you want. Be warned however, if $var is string could not be converted to numeric, you'll get the error, and $var will be reset to 0:
my $var = 'abc123';
print "var = $var\n";
$var += 0;
print "var = $var\n";
logs
var = abc123
Argument "abc123" isn't numeric in addition (+) at test.pl line 7.
var = 0

Perl really only has three types: scalars, arrays, and hashes. And even that distinction is arguable. ;) The way each variable is treated depends on what you do with it:
% perl -e "print 5.4 . 3.4;"
5.43.4
% perl -e "print '5.4' + '3.4';"
8.8

In comparisons it makes a difference if a scalar is a number of a string. And it is not always decidable. I can report a case where perl retrieved a float in "scientific" notation and used that same a few lines below in a comparison:
use strict;
....
next unless $line =~ /and your result is:\s*(.*)/;
my $val = $1;
if ($val < 0.001) {
print "this is small\n";
}
And here $val was not interpreted as numeric for e.g. "2e-77" retrieved from $line. Adding 0 (or 0.0 for good ole C programmers) helped.

Perl is weakly typed and context based. Many scalars can be treated both as strings and numbers, depending on the operators you use.
$a = 7*6; $b = 7x6; print "$a $b\n";
You get 42 777777.
There is a subtle difference, however. When you read numeric data from a text file into a data structure, and then view it with Data::Dumper, you'll notice that your numbers are quoted. Perl treats them internally as strings.
Read:$my_hash{$1} = $2 if /(.+)=(.+)\n/;.
Dump:'foo' => '42'
If you want unquoted numbers in the dump:
Read:$my_hash{$1} = $2+0 if /(.+)=(.+)\n/;.
Dump:'foo' => 42
After $2+0 Perl notices that you've treated $2 as a number, because you used a numeric operator.
I noticed this whilst trying to compare two hashes with Data::Dumper.

Related

How to return only integers from a variable in Shell Script and discard letters and leading zeros?

In my shell script there is a parameter that comes from certain systems and it gives an answer similar to this one: PAR0000008.
And I need to send only the last number of this parameter to another variable, ie VAR=8.
I used the command VAR=$( echo ${PAR} | cut -c 10 ) and it worked perfectly.
The problem is when the PAR parameter returns with numbers from two decimal places like PAR0000012. I need to discard the leading zeros and send only the number 12 to the variable, but I don't know how to do the logic in the Shell to discard all the characters to the left of the number.
Edit Using grep To Handle 0 As Part Of Final Number
Since you are using POSIX shell, making use of a utility like sed or grep (or cut) makes sense. grep is quite a bit more flexible in parsing the string allowing a REGEX match to handle the job. Say your variable v=PAR0312012 and you want the result r=312012. You can use a command substitution (e.g. $(...)) to parse the value assigning the result to r, e.g.
v=PAR0312012
r=$(echo $v | grep -Eo '[1-9].*$')
echo $r
The grep expression is:
-Eo - use Extended REGEX and only return matching portion of string,
[1-9].*$ - from the first character in [1-9] return the remainder of the string.
This will work for PAR0000012 or PAR0312012 (with result 312012).
Result
For PAR0312012
312012
Another Solution Using expr
If your variable can have zeros as part of the final number portion, then you must find the index where the first [1-9] character occurs, and then assign the substring beginning at that index to your result variable.
POSIX shell provides expr which provides a set of string parsing tools that can to this. The needed commands are:
expr index string charlist
and
expr substr string start end
Where start and end are the beginning and ending indexes to extract from the string. end just has to be long enough to encompass the entire substring, so you can just use the total length of your string, e.g.
v=PAR0312012
ndx=$(expr index "$v" "123456789")
r=$(expr substr "$v" "$ndx" 10)
echo $r
Result
312012
This will handle 0 anywhere after the first [1-9].
(note: the old expr ... isn't the fastest way of handling this, but if you are only concerned with a few tens of thousands of values, it will work fine. A billion numbers and another method will likely be needed)
This can be done easily using Parameter Expension.
var='PAR0000008'
echo "${var##*0}"
//prints 8
echo "${var##*[^1-9]}"
//prints 8
var="${var##*0}"
echo "$var"
//prints 8
var='PAR0000012'
echo "${var##*0}"
//prints 12
echo "${var##*[^1-9]}"
//prints 12
var="${var##*[^1-9]}"
echo "$var"
//prints 12

Reason for the text converting from "ZZ" to "1" when i try to add "ZZ"+1

I just want to know the reason if i use the (.) instead i got the result but + is doing arhtematic addition but how is that ASCII addition
my $string = "ZZ";
my $appendstring = $string+1;
print $appendstring;
output
1
Expeccting
ZZ1
First of all, your question is very unclear, and your "example" (if you want to call it that) does not match reality, but in an effort to help whoever stumbles across this question in the future, I'm going to venture an answer anyway.
Let's clear up your example first:
$ perl -lwe '$x = "ZZ"; print $x + 1;'
Argument "ZZ" isn't numeric in addition (+) at -e line 1.
1
What I think you might have meant was:
$ perl -lwe '$x = "ZZ"; print ++$x;'
AAA
And the reason for that is explained in perlop:
The auto-increment operator has a little extra builtin magic to it. If
you increment a variable that is numeric, or that has ever been used
in a numeric context, you get a normal increment. If, however, the
variable has been used in only string contexts since it was set, and
has a value that is not the empty string and matches the pattern
/^[a-zA-Z]*[0-9]*\z/, the increment is done as a string, preserving
each character within its range, with carry.
Edit: your updated question isn't any clearer than your original question, but now I think you're asking about string concatenation, which means you want the string concatenation operator: .
$ perl -lwe '$x = "ZZ"; print $x . 1;'
ZZ1
There is, however, a special case where you can use a string with the numeric addition operator and not generate a warning:
$ perl -lwe '$x = "0 but true"; print $x + 1;'
1
You also mentioned "ASCII addition", but I have no idea what that is or what you mean by that.
According to this
this is the way to concatenate
use strict;
use warnings;
my $x = "4T";
my $y = 3;
print $x . $y; # 4T3
but if you do this:
print $x + $y; # 7
# Argument "4T" isn't numeric in addition (+) at ...
Whenever you use the "+" perl tries to convert both values to numeric, if you provide a string and a number or 2 strings it'll take these as 0 and sum them.
http://ideone.com/0LyEij

Find and replace function that will do simple arithmetic?

I am generating simple SVG diagrams by using sed find and replace on some text input. However, I need a more sophisticated find and replace operation involving simple math, to alter certain X and Y values.
E.g. I need to multiply all Y values by a factor of 0.5 or 0.2 or 0.
Because of how I want this to work, it cannot be achieved with a transform operation within the SVG.*
I just need to be able to find, say, all instances of ([0-9.]*)VERT (in sed speak) and replace with the mathematical result of \1 multiplied by the constant I choose.
You could write a simple perl script. Not sure what determines $factor, but this should at least give you a running start.
#! /usr/bin/perl
my $factor=0.5;
while(my $line=<>) {
if ($line =~ /([0-9.]*)VERT/) {
my $num = $factor * $1;
$line =~ s/([0-9.]*)VERT/${num}VERT/;
}
print $line;
}
Usage: ./scriptname.pl <file_to_process.txt;
perl -ape 's/[0-9.]*(?=VERT)/$& * .5/e' file
hope this works +

string alignment in perl / match alignment

I have two strings $dna1 and $dna2. Print the two strings as concatenated, and then print the second string lined up over its copy at the end of the concatenated strings. For example, if the input
strings are AAAA and TTTT, print:
AAAATTTT
TTTT
this is a self exercise question .. not a homework ,
i tried using index
#!/usr/bin/perl -w
$a ='AAAAAAAAAATTTTTTTTT';
$b ='TTTTTTTTTT';
print $a,"\n";
print ''x index($a,$b),$b,"\n";
but it is not working as needed .help please
Start by checking what index($a,$b) is returning... Perhaps you should pick a $b that's actually in $a!
Then realise that concatenating 10 instances of an empty string is an empty string, not 10 spaces.
This is a fun little exercise. I did this:
perl -lwe'$a="AAAA"; $b="TTTT"; $c = $a.$b; $i = index($c,$b) + length($b);
print $c; printf "%${i}s\n", $b;'
AAAAAAATTTT
TTTT
Note that generally speaking, using the variable names $a through $c is a bad idea, and only acceptable here because it is a one-liner. $a and $b are also reserved variable names used with sort.

How can I repeat a string N times in Perl?

In Python, if I do this:
print "4" * 4
I get
> "4444"
In Perl, I'd get
> 16
Is there an easy way to do the former in Perl?
$ perl -e 'print "4" x 4; print "\n"'
4444
The x operator is documented in perldoc perlop. Here binary means an operator taking two arguments, not composed of bits, by the way.
Binary "x" is the repetition operator. In scalar context or if the
left operand is not enclosed in parentheses, it returns a string consisting
of the left operand repeated the number of times specified by the right
operand. In list context, if the left operand is enclosed in parentheses
or is a list formed by "qw/STRING/", it repeats the list. If the right
operand is zero or negative, it returns an empty string or an empty
list, depending on the context.
print '-' x 80; # Print row of dashes
print "\t" x ($tab/8), ' ' x ($tab%8); # Tab over
#ones = (1) x 80; # A list of 80 1’s
#ones = (5) x #ones; # Set all elements to 5
perl -e is meant to execute Perl code from the command line:
$ perl --help
Usage: perl [switches] [--] [programfile] [arguments]
-e program one line of program (several -e's allowed, omit programfile)
In Perl, you want to use the "x" operator.
Note the difference between
"4" x 4
and
("4") x 4
The former produces a repeated string:
"4444"
the latter a repeated list:
("4", "4", "4", "4")
It's very similar in Perl
print "4" x 4;
FWIW, it’s also print 4 x 4 in Perl.
In general, in Perl, operators are monomorphic, ie. you have different sets of operators for string semantics, for numeric semantics, for bitwise semantics, etc., where it makes sense, and the type of the operands largely doesn’t matter. When you apply a numeric operator to a string, the string is converted to a number first and you get the operation you asked for (eg. multiplication), and when you apply a string operator to a number, it’s turned into a string and you get the operation you asked for (eg. repetition). Perl pays attention to the operator first and the types of the operands only second – if indeed it pays them any mind at all.
This is the opposite of Python and most other languages, where you use one set of operators, and the types of the operands determine which semantics you’ll actually get – ie. operators are polymorphic.
If you want to print 10 character "A"s, you can also do this
perl -e 'print "A" x 10'; echo
Example with output
user#linux:~$ perl -e 'print "A" x 10'; echo
AAAAAAAAAA
user#linux:~$
All answers, given so far, missed mentioning that the operator x does not only work on string literals, but also on variables that are strings or expressions that evaluate to strings like
use feature 'say';
my $msg = "hello ";
say $msg x 2;
say chr(33) x 3;
like this
hello hello
!!!
and, even more important, x does an automatic conversion of expressions into strings if they aren't already (thanks to ggorlen for pointing me into that direction!). So for example
say 4 x 2;
say [$msg] x 2;
will result in something like the following as output
44
ARRAY(0x30ca10)ARRAY(0x30ca10)
Came this way looking for an answer. Didn't quite find what I was looking for so I thought I'd share my learning. I wanted to compose dynamic SQL CRUD statements with the appropriate number of placeholders.
$table = "ORDERS";
#fields = ("ORDER_ID", "SALESMAN_ID", "CUSTOMER_ID", "ORDER_DATE", "STATUS");
$sql = "INSERT INTO $table (" . join(',', #fields) . ') VALUES (' . '?,' x (#fields - 1) . '?)';
print $sql;
The output looks like this...
INSERT INTO ORDERS (ORDER_ID,SALESMAN_ID,CUSTOMER_ID,ORDER_DATE,STATUS) VALUES (?,?,?,?,?)

Resources