blaui has asked for the wisdom of the Perl Monks concerning the following question:

Hello!

I have this e.g. string:

$temp = "BCInletTemperature = 90[C]";
and I want to get out 90
First I split at =
(undef,$tmp) = split(/=/,$tmp[5]);
this works. But how I now can split the contains from $tmp, so that I can get out the 90?
Instead of 90 there can be any other number, and it is possible, that the numer has a decimalpoint, like
BCInletTemperature = 33.56[C]
How can I get out the number?

Regards, blaui

Replies are listed 'Best First'.
Re: how to split a string at [ ?
by Athanasius (Archbishop) on Jul 05, 2018 at 07:04 UTC

    Hello blaui,

    You can just use a regex:

    use strict; use warnings; for my $string ("BCInletTemperature = 90[C]", "BCInletTemperature = 33 +.56[C]") { print "$1\n" if $string =~ / = \s* ([0-9.]+) \[ /x; }

    Output:

    16:59 >perl 1906_SoPW.pl 90 33.56 17:03 >

    The regex says: match an equals sign, followed by zero or more whitespace characters, followed by one or more digit-or-decimal-point characters, followed by a left square bracket; and capture the string of digit-or-decimal-point characters in $1. The /x modifier on the regex means to not match whitespace inside the regex: this just makes the regex easier to read.

    Update: Note that it is necessary to escape the square bracket to tell the regex engine that this is a character to be matched literally, and not the beginning of a character class.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      blaui:   Note that the regex  [0-9.]+ also matches substrings like '1.2.3.4' and '....'.


      Give a man a fish:  <%-{-{-{-<

Re: how to split a string at [ ?
by Corion (Patriarch) on Jul 05, 2018 at 07:07 UTC

    Maybe a better approach instead of split is to match the things you want?

    $temp =~ /BCInletTemperature = ([\d.]+)\[C\]/ or die "Invalid temperature format in '$temp'"; my( $inletTemperature ) = $1;

    In general, both, split and the matching deal with regular expressions. See perlre on how to use them and on how to escape meta-characters.

      Hello!

      The text before the equal sign can differ from BCInletTemperature. It can be another word. But the word will be always low/capital charaters without a blank.


      Can I get this with the above too?

      Regards, blaui

        Yes, see perlre on how "alternations" work:

        $temp =~ /(BCInletTemperature|someOtherTemperature|aThirdTemperatu +reName) = ([\d.]+)\[C\]/ or die "Invalid temperature format in '$temp'"; my( $temperatureType, $temperatureValue ) = ($1,$2);

        But maybe you want a more generic parser that will capture any word on the left hand side of the "=" sign and any number on the right hand side. Then you can use the \w character class or the [A-Za-z] character class (again, see perlre) for matching any word on the left hand side:

        $temp =~ /(\w+) = ([\d.]+)\[C\]/ or die "Invalid temperature format in '$temp'"; my( $temperatureType, $temperatureValue ) = ($1,$2);
Re: how to split a string at [ ?
by Laurent_R (Canon) on Jul 05, 2018 at 07:52 UTC
    Hi blaui,

    first, a comment on the code that you've shown. This:

    (undef,$tmp) = split(/=/,$tmp[5]);
    does not work with the string example that you have provided. In fact, worse than that, $tmp[5] is not defined at this point with the code that you have shown.

    Next, I definitely agree with my fellow monks above that using a regex to capture the numerical value between the = sign and the opening square bracket is the simplest solution.

    If, however, you want to continue using split, take a look at this possible solution illustrated under the Perl debugger:

    DB<1> $temp = "BCInletTemperature = 90[C]"; DB<2> (undef,$tmp) = split /=/, $temp; DB<3> print $tmp 90[C] DB<4> temperature = (split /\[/, $tmp)[0]; DB<5> p $temperature 90
    Note however that with this solution, the $temperature variable will contain leading space:
    DB<6> p "<$temperature>"; < 90>
    which may or may not be a problem for you, depending on what you do afterwards with that variable.

    It is quite easy to get rid of that leading space if needed, but the simplest way is to use a regex. So, why not start with a simple regex anyway?

Re: how to split a string at [ ?
by AnomalousMonk (Archbishop) on Jul 05, 2018 at 13:14 UTC

    Another regex approach, with broader matching and some negative cases. See Regexp::Common.

    c:\@Work\Perl\monks>perl -wMstrict -le "use Regexp::Common; ;; my @records = ( 'BCInletTemperature = 90[C]', 'BCInletTemperature = 33.56[C]', 'Whatever = -.012[C]', 'Wrong = 90 [C]', 'AlsoWrong = 9.0.1[C]', ); ;; for my $record (@records) { printf qq{'$record' -> }; my $got_temp = my ($temp) = $record =~ m{ = \s+ ($RE{num}{real}) \[ }xms; if ($got_temp) { print qq{temp '$temp'}; } else { print 'no got temp'; } } " 'BCInletTemperature = 90[C]' -> temp '90' 'BCInletTemperature = 33.56[C]' -> temp '33.56' 'Whatever = -.012[C]' -> temp '-.012' 'Wrong = 90 [C]' -> no got temp 'AlsoWrong = 9.0.1[C]' -> no got temp
    Note that the regex might easily be extended to validate the entire record.


    Give a man a fish:  <%-{-{-{-<

      Hello!

      Thanxs all a lot for the many suggestions. Because it seems the more felxible, I started to try with the above Regexp::Common.


      I modified it a littel bit.
      $tmp[5] = "BCInletTemperature = 90[C]"; print "$tmp[5] xx\n"; $temp = $tmp[5] =~ m{ = \s+ ($RE{num}{real}) \[ }xms; print "xxx $temp xxx\n";
      But running it gives:
      Name "charnames::CARP_NOT" used only once: possible typo at /usr/lib/p +erl5/5.18.2/Carp.pm line 437. Name "Regexp::Common::delimited::CARP_NOT" used only once: possible ty +po at /usr/lib/perl5/5.18.2/Carp.pm line 437. BCInletTemperature = 90[C] xx xxx 1 xxx
      Perl is
      perl --version This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-li +nux-thread-multi
      at openSUse Leap 42.3.
      Do I need a newer version?

      Regards, buchi

        Do I need a newer version?

        No, but you do need to remember to put the brackets around $temp when you assign to it in order to ensure list context. You should also provide an SSCCE rather than 4 lines out of context as something could be wrong in the code you aren't showing too.

        Name "charnames::CARP_NOT" used only once: possible typo at /usr/lib/p +erl5/5.18.2/Carp.pm line 437. Name "Regexp::Common::delimited::CARP_NOT" used only once: possible ty +po at /usr/lib/perl5/5.18.2/Carp.pm line 437.

        Those are warnings, not errors, and I can't seem to be able to reproduce them here (don't have 5.18.2 handy though). Are you perhaps using perl -w on the command line or on the shebang line? In that case, see What's wrong with -w and $^W and use warnings; instead.

        The other issue with that code is that $string=~/(regex)/ won't return the match(es) unless you use it in list context, but my $temp = ... puts it in scalar context. To put the right-hand side into list context, use my ($temp) = $string =~ /(regex)/;.