Perl regular expression for string and digits - match only last 6 digits

Viewed 366

I need to extract last 6 digits from name of file (which is date) and regex for me doesnt work.

The string is: name_of_file0000000546210618.A001.6476871457

I need to contains just this: name_of_file210618.A001

My regex is: name_of_file\(\d{6}).A\d{3} - doesn't work

I tried also: name_of_file(\d{6}).A\d{3} - doesn't work

More details:

We already used name_of_file(\d{6}).A\d{3} and it has been working for more than 3 years. The string in those cases is just name_of_file210618.A001.6476871457 and the regex takes just this: name_of_file210618.A001. And that is exactly what I need in this case, I need to handle the digits before 210618.

3 Answers

Delete all digits followed by 6 digits:

perl -pe 's/\d*(?=\d{6})//' <<< 'name_of_file0000000546210618.chardigits.digits'

You need

name_of_file\K\d*(?=\d{6}\.A\d{3})

Replace with an empty string. See the regex demo. Details:

  • name_of_file - a specific string
  • \K - match reset operator discarding the text matched so far from the overall match memory buffer
  • \d* - zero or more digits
  • (?=\d{6}\.A\d{3}) - a positive lookahead that requires six digits, .A and three digits to appear immediately to the right of the current location.

See the Perl demo online:

#!/usr/bin/perl
use feature 'say';
use strict;
use warnings;
 
my $str = "name_of_file0000000546210618.A001.6476871457";
say $str =~ s/name_of_file\K\d*(?=\d{6}\.A\d{3})//r;

Output:

name_of_file210618.A001.6476871457

The reason your regex

name_of_file\(\d{6}).A\d{3}
#           ^^--- escaped parenthesis

Does not work is because it expects a literal parenthesis ( in your string. Since there are none, this will never match.

This regex

name_of_file(\d{6}).A\d{3} 

Will not match, since you have it "anchored" between name_of_file and .A, with no allowance for characters in between.

The simplest fix to allow extra filler numbers is to simply add \d* before your capture area. You should also escape . since it is a regex meta character that means "match any character except newline".

name_of_file\d*(\d{6})\.A\d{3}

This will now allow the regex to match more loosely with strings such as

name_of_file0000000546210618.A001.6476871457
#           ^^^^^^^^^^---- unneeded numbers

Similarly, you could just remove the anchor before the numbers

(\d{6})\.A\d{3}

It is strange to me to have the string name_of_file in a regex. If it is a placeholder for an actual file name, it would mean that you hard code a file name in your regex, meaning it will only match that exact filename, and nothing else. Usually, you want regexes to match a number of different type of strings. I would expect a regex to match different file names to look something like:

 [\pL_]+\d*(\d{6})\.A\d{3}
#^^^^^^-- matching letters and underscore

It seems like what you need to capture, however, is not the number, like your regex shows, but the filename also, in a string like this: name_of_file210618.A001. In that case, you would need to perform some more operations. It might be possible to execute with a substitution to remove unwanted characters, but it is much simpler to just use a regex and concatenation, like this

use strict;
use warnings;
use Data::Dumper;

while (<DATA>) {
    my ($name, $num) = /([\pL_]+)\d*(\d{6}.A\d{3})/;
    my $str = join '', $name, $num;
    print Dumper $str;
}

__DATA__
name_of_file210618.A001.6476871457
name_of_file0000000546210618.A001.6476871457
foo_of_bar210618.A001.6476871457

This will print

$VAR1 = 'name_of_file210618.A001';
$VAR1 = 'name_of_file210618.A001';
$VAR1 = 'foo_of_bar210618.A001';
Related