What is the easier way to replace non-numeric characters with a space in a string in perl?

Viewed 221

I have strings like the following line:

2020/07/02  03:15:00    CAT 14,3    km/h    OK  95,87   °   OK  14,1    °C  OK  75,83   % RH    OK  894,4   mbar    OK  *   mm  MISSING *   °C  MISSING *   °C  MISSING 9,9 °C  OK  0,0 W/m²    OK

I want to replace all non-numeric characters, and remain with only numbers separated by spaces. The above data line should be:

2020 07 02  03:15   14.3    95.87   14.1    75.83   894.4   -99.    -99.    9.9     0.0 

I have tried replacements like in my MWE below. The code runs without any error but nothing is replaced. I have also appended the data, which the perl code reads from a file. My problems are two-fold:

  1. Why is no replacement done?
  2. How do I compose the replacement regex?

I will appreciate help

#!/usr/bin/perl -w

use strict;
use warnings;
my $IN=IO::File->new("textstr.txt", q{<}) or die "open 'textstr.txt': failed $! ($^E)";
my @textstr=<$IN>;


foreach my $textstr(@textstr){
chomp $textstr;
$textstr=~ s/\/\:\°\%//g; #replace all these characters by space
$textstr=~ s/km\/h//g;
$textstr=~ s/W\/m\^²//g;
$textstr=~ s/\*/-99.0/g;  #replace * by -99. as missing value
$textstr=~ s/\,/\./g;    #replace , as decimal point
$textstr=~ s/a-z||A-Z//g;

print "$textstr\n";
}

I am not able to attach the data, so I append it below

2020/07/02      07:00:00        CAT     9,3     km/h    OK      129,41  °       OK      9,2     °C      OK      98,24   % RH    OK      895,9   mbar    OK      *       mm      MISSING *       °C      MISSING *       °C      MISSING 8,9     °C      OK      0,5     W/m²    OK
2020/07/02      07:15:00        CAT     8,2     km/h    OK      116,25  °       OK      10,5    °C      OK      94,73   % RH    OK      896,3   mbar    OK      *       mm      MISSING *       °C      MISSING *       °C      MISSING 9,7     °C      OK      79,0    W/m²    OK
2020/07/02      07:30:00        CAT     8,2     km/h    OK      116,25  °       OK      10,5    °C      OK      94,73   % RH    OK      896,3   mbar    OK      *       mm      MISSING *       °C      MISSING *       °C      MISSING 9,7     °C      OK      79,0    W/m²    OK
2020/07/02      07:45:00        CAT     8,2     km/h    OK      116,25  °       OK      10,5    °C      OK      94,73   % RH    OK      896,3   mbar    OK      *       mm      MISSING *       °C      MISSING *       °C      MISSING 9,7     °C      OK      79,0    W/m²    OK
2020/07/02      08:00:00        CAT     8,2     km/h    OK      116,25  °       OK      10,5    °C      OK      94,73   % RH    OK      896,3   mbar    OK      *       mm      MISSING *       °C      MISSING *       °C      MISSING 9,7     °C      OK      79,0    W/m²    OK
2020/07/02      08:15:00        CAT     16,2    km/h    OK      96,76   °       OK      15,4    °C      OK      72,39   % RH    OK      896,8   mbar    OK      0,0     mm      OK      8,7     °C      OK      27,1    °C      OK      10,5    °C      OK      275,0   W/m²    OK
2020/07/02      08:30:00        CAT     16,2    km/h    OK      96,76   °       OK      15,4    °C      OK      72,39   % RH    OK      896,8   mbar    OK      0,0     mm      OK      8,7     °C      OK      27,1    °C      OK      10,5    °C      OK      275,0   W/m²    OK
2020/07/02      08:45:00        CAT     16,2    km/h    OK      96,76   °       OK      15,4    °C      OK      72,39   % RH    OK      896,8   mbar    OK      0,0     mm      OK      8,7     °C      OK      27,1    °C      OK      10,5    °C      OK      275,0   W/m²    OK
2020/07/02      09:00:00        CAT     16,2    km/h    OK      96,76   °       OK      15,4    °C      OK      72,39   % RH    OK      896,8   mbar    OK      0,0     mm      OK      8,7     °C      OK      27,1    °C      OK      10,5    °C      OK      275,0   W/m²    OK
1 Answers

You need to use character classes for /:°% and a-z:

foreach my $textstr(@textstr){
    chomp $textstr;
    $textstr=~ s/[\/:°%]/ /g; #replace all these characters by space
    $textstr=~ s/km\/h//g;
    $textstr=~ s/W.*//;
    $textstr=~ s/\*/-99.0/g;  #replace * by -99. as missing value
    $textstr=~ s/,/./g;    #replace , as decimal point
    $textstr=~ s/[a-z]//gi;
    print "$textstr\n";
}

For /:°%, you also need to add a space in the replacement.

For a-z, you can simplify using the case-insensitive modifier i.

I resorted to extreme measures to get rid of the pesky superscript ². You might want to review that one.

I also eliminated some of the unnecessary backslashes.


This gets you most of the way there. It replaces all colons with a space, but your output preserves the 1st colon and deletes the 2 digits after the 2nd colon.

Related