learner@perl has asked for the wisdom of the Perl Monks concerning the following question:

Hi Masters,

i am reading file names from the directory and i am putting some conditions while reading a file names

if ( ( $file =~ m/^CHECK*/ ) && ( $file =~ m/.txt$/ ) ) { print "name is = $file\n"; }

The file names in directory are like

CHECK_CH.ABC12_A1.txt CHECK_CH.ABC12.txt

I want to read all the files with first word as CHECK and last word as .txt

I want only .txt should display not A1.txt, how can i exclude the that

any suggestions please

but when i execute the code,i am getting all the files .txt and A1.txt

The output is

CHECK_CH.ABC12_A1.txt CHECK_CH.ABC12.txt

I am expecting output as:

CHECK_CH.ABC12.txt

Replies are listed 'Best First'.
Re: how to check whether a particular word exists in filename
by Happy-the-monk (Canon) on Jul 03, 2013 at 19:22 UTC

    I want only .txt should display not A1.txt, how can i exclude the that

    * is a quantifier in regex, you probably did not mean to use it there.

    This might do: if ( $file =~ m/^CHECK.*\.txt$/ and $file !~ m/A1\.txt$/ ) { ...

    !~ to negate the "A1.txt" part.

    Cheers, Sören

    (hooked on the Perl Programming language)

Re: how to check whether a particular word exists in filename
by kennethk (Abbot) on Jul 03, 2013 at 19:24 UTC
    There are a myriad of ways to solve this issue, but I read your criterion as 'Ends with .txt but not with A1.txt'. The easiest solution here would be to add an additional test to your set:
    if ( ( $file =~ m/^CHECK*/ ) && ( $file =~ m/\.txt$/ ) && ( $file !~ m +/A1\.txt$/ ) ) {

    Note that I've added a backslash before your .. If you intend to match literal periods, you need to escape them because period is on of the Metacharacters; it matches anything except a new line.


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: how to check whether a particular word exists in filename
by Laurent_R (Canon) on Jul 03, 2013 at 22:04 UTC

    I wonder how you generate your list of files.

    Using the glob function enables you to use a finename mask giving you only the files matching this mask. This makes thing easier For example:

    my @file_list = glob "./mypath/CHECK*.txt";

    This filters out all filenames that do not start with CHECK and end with .txt. Note that, in this case, the "CHECK*.txt" string is not a Perl regex, it is an operating system file matching pattern (meaning inter allia that, here, the * stands for any group of characters and that you don't have to escape the dot). The glob function has the additional advantage that it will return you a list of files with their relative path, which is usually handy if you need to fo further work on these files.

    This glob function is quite practical, but this will not solve the issue of the files that you want to exclude, but you are not stating clearly the rules for exclusion (just one example is definitely not a spec). Assuming for the sake of example that having a second underscore in the name is a reason for exlusion, you could do this in one go as follows:

    my @file_list = grep {! /_.*_/} glob "./mypath/CHECK*.txt";

    This single line above replaces the opendir and readdir statements and the regexes on the file names. (The regex in the grep block is not particularly efficient and can be improved if needed but it is just given as a very simple example.)

Re: how to check whether a particular word exists in filename
by kcott (Archbishop) on Jul 04, 2013 at 04:22 UTC

    G'day learner@perl,

    Firstly, it looks like your initial problems have been pointed out be Happy-the-monk. Just adding a little more detail:

    • K* means match zero or more K characters.
    • . means match any character (except a newline).
    • K.* means match a K character followed by zero or more non-newline characters.
    • To match a single . you can escape it (\.) or put it in a character class ([.]). [I think the latter stands out more and makes the intent more obvious but either is fine.]

    To match filenames starting with CHECK and ending with .txt, this would be fine:

    /^CHECK.*[.]txt$/

    To exclude those with A1 before the .txt, you can insert what's known as a zero-width negative look-behind assertion which looks like (?<!pattern). The name's quite a mouthful but don't be put off by that: it's just a name. Take a look at Look-Around Assertions in perlre - Extended Patterns for a more detailed description (as well as similar positve and look-ahead assertions).

    So, we want to assert that the pattern matches if we look-behind .txt and don't find (negative) A1. We write that like (?<!A1) and place it between /^CHECK.* and [.]txt$/ where it effectively takes up no space (zero-width). That gives:

    /^CHECK.*(?<!A1)[.]txt$/

    You haven't made it clear whether there must be any characters between CHECK and .txt; if so, change zero or more non-newline characters (.*) to one or more non-newline characters (.+).

    Here's my test:

    $ perl -Mstrict -Mwarnings -E ' my @test_filenames = qw{ CHECK_CH.ABC12_A1.txt CHECK_CH.ABC12.txt HECK_CH.ABC12_A1.txt HECK_CH.ABC12.txt CHECK_CH.A1.txt CHECK_CH..txt CHECK.txt CHECKA1.txt CHECK.ABC12.txt }; say "*** May be nothing between CHECK & .txt ***"; for (@test_filenames) { next unless /^CHECK.*(?<!A1)[.]txt$/; say; } say "*** Must be something between CHECK & .txt ***"; for (@test_filenames) { next unless /^CHECK.+(?<!A1)[.]txt$/; say; } ' *** May be nothing between CHECK & .txt *** CHECK_CH.ABC12.txt CHECK_CH..txt CHECK.txt CHECK.ABC12.txt *** Must be something between CHECK & .txt *** CHECK_CH.ABC12.txt CHECK_CH..txt CHECK.ABC12.txt

    -- Ken

Re: how to check whether a particular word exists in filename
by Preceptor (Deacon) on Jul 03, 2013 at 19:24 UTC

    Edited, because it's wrong.

      "...but not 'CHECK_ABC123_A1.txt' "

      Nope! Not true.

      C:\>perl -E "my $s='CHECK_ABC123_A1.txt';say $s if ($s =~ m/^CHECK_(\w ++)\.txt/ );" CHECK_ABC123_A1.txt

      or, alternately,

      #!/usr/bin/perl use 5.016; use strict; use warnings; # 1042260 my $s='CHECK_ABC123_A1.txt'; if ( $s =~ m/^CHECK_(\w+)\.txt/ ) { say "\t \$1 is: $1\n\t and the regex matched the source string."; } else { say "\t Nope. Regex didn't match \$s."; } =head OUTPUT: $1 is: ABC123_A1 and the regex matched the source string. =cut

      Pls test your advice... (unless you were trying to get a clueless OP to turn in homework with an error).


      If you didn't program your executable by toggling in binary, it wasn't really programming!

        Nope! Not true.

        That is because in the character class [A-Za-z0-9] there is no underscore, and Preceptor assumed that would be equivalent to \w .
        \w , however, is [A-Za-z0-9_] and thus includes the underscore.

        Cheers, Sören

        (hooked on the Perl Programming language)

Re: how to check whether a particular word exists in filename
by Shuraski (Scribe) on Jul 04, 2013 at 15:20 UTC

    Or you could simply do this at the command line:

    $ ls your/path/to/directory/ | grep .txt | grep CHECK