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

Hello All,

I have file named 'testfile.class'.
I need to find all related files of testfile.class with a $ sign in between in a directory.
Eg: te$stfile.class or t$stfile.class or testfi$le.class in a directory, and here the '$ can come anywhere.
I know that I can use the Find:file package like this
$file = "testfile.class";
find( sub { /$file/ && print "$File::Find::name\n" },$destDir);


But how can I find file with the $ sign inside?
Can we do with a regexp?

Thanks,
Dan.

Replies are listed 'Best First'.
Re: file$name.class find - regexp ?
by Corion (Patriarch) on Sep 27, 2008 at 06:13 UTC

    Please read perlre to learn how to escape strings. You will likely want to use quotemeta respectively the \Q...\E string escapes to escape regex-special characters from your search string:

    use strict; use File::Find; $file = 'test$file.class'; # note that you need to use single quotes h +ere find( sub { /\Q$file\E/ && print "$File::Find::name\n", $destDir });
Re: file$name.class find - regexp ?
by JavaFan (Canon) on Sep 27, 2008 at 00:52 UTC
    In one of your examples, '$' replaces a character in 'testfile'; in two others, '$' is just put in between 'testfile'. And in one example, 'class' becomes 'call'.

    If it were just a '$' put in, it would be easy: for each file in the directory, remove the '$' from the name (if any), then check if the result equals 'testfile.class'.

    But such an approach would fail 2 out of your 3 examples.

      Thanks for your reply...sorry it should be class.
      But I guess my question is I know the base file name 'testfile.class'. I need to find if there are any other files exists in the directory with a $ sign in between of testfile.class. $ can come anywhere...
      like, I know testfile.class and I want to any related files like test$file.class or testfi$le.class exists in the same directory...
      Thanks bunch..
        As I said, look at each file in the directory. If it contains a '$', remove it. If the result equals 'testfile.class', the original was 'testfile.class' with a '$' somewhere in it.
        You still haven't answered JavaFan's original question: will the '?' character be inserted into the string, leaving all the other characters and simply changing some of their offsets in the string, or may the '?' replace one of the other characters in the string, or both?

        In the first case, the answer is fairly straightforward, and JavaFan has given it to you. In the other cases, the problem is a bit more complex.

        Can you please be more specific about your exact problem?

Re: file$name.class find - regexp ?
by toolic (Bishop) on Sep 27, 2008 at 16:15 UTC
    You could use File::Find to solve your problem. But, if you have no need to find files recursively throughout a directory tree (and you have not given any indication that you need to), then I would recommend using opendir and readdir instead.

    This approach still does not use a single regex to match the filenames, but it is worth considering. This code is UNTESTED:

    use File::Basename; # Get all files in the directory which look like t*.class opendir my $DIR, $dirname or die "can not open $dirname: $!"; my @files = grep { -f "$dirname/$_" } # choose only plain files grep { /t.*\.class$/ } # pattern match readdir $DIR; closedir $DIR; # Now select only those files whose name has exactly one $ # between the "t" and ".class" my @files2; for my $file (@files) { my $base = basename($file); $base =~ s/\$//; push @files2, $file if $base eq 'testfile.class'; }
Re: file$name.class find - regexp ?
by AnomalousMonk (Archbishop) on Sep 29, 2008 at 03:26 UTC
    This thread may be dead, but I'll add my comment anyway.

    Assume the problem is to recognize that two strings, s1 and s2, are associated when the strings are exactly the same except that a '$' character has been: inserted exactly once anywhere (including at the ends) in s2, or substituted exactly once for any character in s2.

    Then a solution might make use of the idea of Levenshtein Distance (LD), which, as I understand it (and you would do well to double-check my understanding), is the number of characters that need to be inserted, changed or deleted in a string in order to transform it into another string.

    So if s1 has no '$' character in it, and s2 has at least one '$', and the LD between s1 and s2 is exactly one, then s2 is exactly like s1 except that exactly one '$' has been inserted or substituted into s2.

    Note, however, that 'test.ext' matches with 'test$ext'.

    I am using the expression $try =~ m{ \$ }xms in the function acquired_1_dollar() because the OPer asked for something using a regex. This might more straightforwardly be index($try, '$') >= 0. I can't think of any (fairly simple) way to do the entire match using only a regex.

    Also, I use Text::LevenshteinXS only because I could not get Text::Levenshtein, both from the ActiveState repository, to work.

    C:\@Work\Perl\monks\dani_cv>perl -wMstrict -le "use Text::LevenshteinXS qw(distance); my $base = shift; print qq(\noutput:); for my $try (@ARGV) { my $no = acquired_1_dollar($base, $try) ? q{} : q{NO }; print qq{$base <> $try: ${no}match}; } sub acquired_1_dollar { my ($base, $try) = @_; return $try =~ m{ \$ }xms && distance($base, $try) == 1; } " test.ext $test.ext te$st.ext test$.ext test.$ext test.e$xt test.ext$ $est.ext te$t.ext tes$.ext test$ext test.$xt test.e$t test.ex$ test.ext tost.ext te$t$.ext tet.ext t$t.ext tes$t$xt test$e$t "" $ test wertyu wert$yu w$er$tyu output: test.ext <> $test.ext: match test.ext <> te$st.ext: match test.ext <> test$.ext: match test.ext <> test.$ext: match test.ext <> test.e$xt: match test.ext <> test.ext$: match test.ext <> $est.ext: match test.ext <> te$t.ext: match test.ext <> tes$.ext: match test.ext <> test$ext: match test.ext <> test.$xt: match test.ext <> test.e$t: match test.ext <> test.ex$: match test.ext <> test.ext: NO match test.ext <> tost.ext: NO match test.ext <> te$t$.ext: NO match test.ext <> tet.ext: NO match test.ext <> t$t.ext: NO match test.ext <> tes$t$xt: NO match test.ext <> test$e$t: NO match test.ext <> : NO match test.ext <> $: NO match test.ext <> test: NO match test.ext <> wertyu: NO match test.ext <> wert$yu: NO match test.ext <> w$er$tyu: NO match