How can I convert a string to a float with Perl? - perl

Is there any function like int() which can convert a string to float value?
I'm currently using the following code:
$input=int(substr($line,1,index($line,",")-1));
I need to convert the string returned by substr to float.

Just use it. In Perl, a string that looks like a number IS a number.
Now, if you want to be sure that the thing is a number before using it then there's a utility method in Scalar::Util that does it:
use Scalar::Util qw/looks_like_number/;
$input=substr($line,1,index($line,",")-1);
if (looks_like_number($input)) {
$input += 1; # use it as a number!
}
Based on the sample input you left in the comments, a more robust method of extracting the number is:
$line =~ /([^\[\],]+)/; # <-- match anything not square brackets or commas
$input = $1; # <-- extract match

I don't know what your data looks like, but you do realize that the third argument to substr is a length, not a position, right? Also, the first position is 0. I suspect you aren't getting the data you think you are getting, and it mostly accidently works because you are starting at the beginning of the string and are only off by one.

Related

truncate string in perl into substring with trailing elipses

I'm trying to truncate a string in a select input option using perl if it is longer than a set value, though i can't get it to work correctly.
my $value = defined $option->{value} ? $option->{value} : '';
my $maxValueLength = 50;
if ($value.length > $maxValueLength) {
$value = substr $value, 0, $maxValueLength + '...';
}
Another option is regex
$string =~ s/.{$maxLength}\K.*/.../;
It matches any character (.) given number of times ({N}, here $maxLength), what is the first $maxLength characters in $string; then \K makes it "forget" all previous matches so those won't get replaced later. The rest of the string that is matched is then replaced by ...
See Lookaround assertions in perlre for \K.
This does start the regex engine for a simple task but it doesn't need any conditionals -- if the string is shorter than the maximum length the regex won't match and nothing happens.
Your code has several syntax errors. Turn on use strict and use warnings if you don't have it, and then read the error messages it tells you about. This is a bit tricky because of Perl's very complex syntax (see also Damian Conway's keynote from the 2020 Perl and Raku Conference), but it boils down to these:
Use of uninitialized value in concatenation (.) or string at line 7
Argument "..." isn't numeric in addition (+) at line 8
I've used the following adaption of your code to produce these
use strict;
use warnings;
my $value = '1234567890' x 10;
my $maxValueLength = 50;
if ( $value.length > $maxValueLength ) {
$value = substr $value, 0, $maxValueLength + '...';
}
print $value;
Now let's see what they mean.
The . operator in Perl is a concatenation. You cannot use it to call methods, and length is not a method on a string. Perl thinks you are using the built-in length (a function, not a method) without an argument, which makes it default to $_. Most built-ins do this, to make one-liners shorter. But $_ is not defined. Now the . tries to concatenate the length of undef to $value. And using undef in a string operation leads to this warning.
The correct way of doing this is length $value (or with parentheses if you prefer them, length($value)).
The + operator is not concatenation (we just learned that the . is). It's a numerical addition. Perl is pretty good at converting between strings and numbers as there aren't really any types, so saying 1 + "5" would give you 6 without problems, but it cannot do that for a couple of dots in a string. Hence it complains about a non-number value in an addition.
You want the substring with a given length, and then you want to attach the three dots. Because of associativity (or stickyness) of operators you will need to use parentheses () for your substr call.
$value = substr($value, 0, $maxValueLength) . '...';
To find a length of the string use length(STRING)
Here is the code snippet how you can modify the script.
#!/usr/bin/perl
use strict;
use warnings;
use feature qw(say);
my $string = "abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz";
say "length of original string is:".length($string);
my $value = defined $string ? $string : '';
my $maxValueLength = 50;
if (length($value) > $maxValueLength) {
$value = substr $value, 0, $maxValueLength;
say "value:$value";
say "value's length:".length($value);
}
Output:
length of original string is:80
value:abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvw
value's length:50

Extract substring using two delimiters and NO REGEX

I have a function whose aim is to extract a substring found between two delimiters. I would use regex but in this case I have explicit instructions not to use them.
I had a simpler and more elegant solution which was just one line but I cannot for the life of me remember or find it.
sub findBetween {
my ($theString,$delimiter1,$delimiter2) = (#_);
my $tmp = substr($theString, index($theString,$delimiter1)+length($delimiter1));
$tmp = substr($tmp, 0, index($tmp,$delimiter2));
return $tmp;}
Thank you for taking a look at this issue, I am aware it is very basic and somewhat redundant. What I need is a simpler solution involving perl basic functions and no regex.
You can use two index() calls to locate both delimiters and use indexes to extract string between them,
sub findBetween {
my ($theString,$delimiter1,$delimiter2) = #_;
my $i1 = index($theString, $delimiter1, 0) + length($delimiter1);
my $i2 = index($theString, $delimiter2, $i1);
return substr($theString, $i1, $i2-$i1);
}
print findBetween("111--2222~~333", "--", "~~"), "\n";
output
2222
I would simply use index
use strict;
use warnings;
my $string = "hello my world";
my $substr = "my";
if (index($string, $substr) != -1) {
print "$substr found in $string";
}
Extract from perldoc
• index STR,SUBSTR,POSITION
• index STR,SUBSTR
The index function searches for one string within another, but without the wildcard-like behavior of a full regular-expression pattern match. It returns the position of the first occurrence of SUBSTR in STR at or after POSITION. If POSITION is omitted, starts searching from the beginning of the string. POSITION before the beginning of the string or after its end is treated as if it were the beginning or the end, respectively. POSITION and the return value are based at zero. If the substring is not found, index returns -1.

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',

Perl converts to int wrong but only with specific number

the following perl code converts a float number to the wrong integer number
use strict;
my $zahl =297607.22000;
$zahl=$zahl * 100;
print "$zahl\n";
my $text=sprintf ("%017d",$zahl);
print $text;
The output of this is :
29760722
00000000029760721
The thing is, you can change the given number to other numbers and it works.
Any idea what is wrong here or does Perl simply do it wrong?
Thanks for your help!
This is related to a FAQ (Why am I getting long decimals). $zahl is not rounded properly, it is rounded down to the next lower integer.
22/100 is a periodic number in binary just like 1/3 is a periodic number in decimal. It would take infinite storage to store it exactly in a floating point number.
$ perl -e'$_="297607.22000"; $_*=100; printf "%.20f\n", $_'
29760721.99999999627470970154
int and sprintf %d truncate decimals, so you end up with 29760721. print and sprintf %f round, so you can get the desired result.
$ perl -e'$_="297607.22000"; $_*=100; printf "%017.0f\n", $_'
00000000029760722
When you are doing your floating point multiplication by 100 the result will be something like 29760721.9999999963. Then when you do the %d conversion to an integer this is truncated to 29760721.
Try sprintf('%.10f', $zahl) and you should be able to see this.
You have to be really careful with floating point numbers and treating them as fixed point. Due to various conversions that may take place in the builtins, there may be times where one integer conversion is not exactly the same as another. It appears that this happens many times with x.22 numbers:
use strict;
my $n = 0;
for (0 .. 10_000_000) {
my $float = 100 * "$_.22";
my $str = "$float";
my $int = int $float;
if ($str ne $int) {
$n++;
#say "$float, $str, $int";
}
}
say "n = $n";
which prints
n = 76269
on my system.
A careful look at the Perl source would be required to see where the exact conversion difference is.
I would recommend that if you are going to be working with fixed point numbers, to convert them all to integers (using a common conversion function, preferably looking at the source numbers as strings), and then work with them all under the use integer; pragma which will disable floating point numbers.

How do I get the length of a string in Perl?

What is the Perl equivalent of strlen()?
length($string)
perldoc -f length
length EXPR
length Returns the length in characters of the value of EXPR. If EXPR is
omitted, returns length of $_. Note that this cannot be used on an
entire array or hash to find out how many elements these have. For
that, use "scalar #array" and "scalar keys %hash" respectively.
Note the characters: if the EXPR is in Unicode, you will get the num-
ber of characters, not the number of bytes. To get the length in
bytes, use "do { use bytes; length(EXPR) }", see bytes.
Although 'length()' is the correct answer that should be used in any sane code, Abigail's length horror should be mentioned, if only for the sake of Perl lore.
Basically, the trick consists of using the return value of the catch-all transliteration operator:
print "foo" =~ y===c; # prints 3
y///c replaces all characters with themselves (thanks to the complement option 'c'), and returns the number of character replaced (so, effectively, the length of the string).
length($string)
The length() function:
$string ='String Name';
$size=length($string);
You shouldn't use this, since length($string) is simpler and more readable, but I came across some of these while looking through code and was confused, so in case anyone else does, these also get the length of a string:
my $length = map $_, $str =~ /(.)/gs;
my $length = () = $str =~ /(.)/gs;
my $length = split '', $str;
The first two work by using the global flag to match each character in the string, then using the returned list of matches in a scalar context to get the number of characters. The third works similarly by splitting on each character instead of regex-matching and using the resulting list in scalar context