Showing posts with label perl script. Show all posts

Iterating a string through each character

In general if there is a need for us to iterate though a string character by character, then we normally split the string using a statement like:
@chars=split("",$var);
Now after the array is created we iterate through that array.But an easy way of doing this in Perl without creating an array is :
while ($var =~ /(.)/sg) {
   my $char = $1;
   print $char."\n"
}
Below is the explanation for the same:
$var =~ /(.)/sg
Match any character though out the string and round braces "()" captures the matched character.
/s 
Treat string as single line. That is, change "." to match any character whatsoever, even a newline, which normally it would not match.
/g
Match all occurrences of the regexp throughout the line instead of only the first occurrence.

Searching multiple strings in multiple files in a directory

I have a list of strings in a file separated by a new line.
for example:
input.txt
temp1
temp2
temp3
Now I have a directory with multiple dat files like:
>ls -1 *.dat
one.dat
two.dat
three.dat
And many more dat like like above with random names. Now I want to search for all the strings in input.txt in all the dat files present in  directory(let's say current working directory).This is what I came up with:
create a perl script given below and name it as anything you wish(I named here as temp.pl).place the file input.txt in the current working directory.
#!/usr/bin/perl -w

open (INP,"input.txt") or die $!;
while(<INP>)
{
my $cmd="find . -name \"*.dat\"|xargs grep -w -i $_";
my $output=`$cmd`;
 if($output!~/^\s*$/)
 {
 print $_."\n";
 print "------------------\n";
 print $output."\n";
 print "-------------------\n";
 }
}
exit;
Run this script as :
>./temp.pl
This solved my need.I hope it solves yours too :)

Consequetive pattern match in Perl

Make a pattern that will match three consecutive copies of whatever is currently contained in $what. That is, if
$what="fred" , your pattern should match "fredfredfred".
If
$what is "fred|barney", your pattern should match
"fredfredbarney" and
"barneyfredfred" and
"barneybarneybarney" and  many other variations.
Well, This is quite tricky. But the magic match to do over here is :
/($str){3}/

 Below is the example code:
#!/usr/bin/perl
use warnings;
use strict;
# notice the example has the `|`. Meaning
# match "fred" or "barney" 3 times.
my $str = 'fred|barney';
my @tests = qw(fred fredfredfred barney barneybarneybarny barneyfredbarney);
for my $test (@tests) {
if( $test =~ /^($str){3}$/ ) {
print "$test matched!\n";
} else {
print "$test did not match!\n";
}
}

Below is the execution:
> ./temp9.pl
fred did not match!
fredfredfred matched!
barney did not match!
barneybarneybarny did not match!
barneyfredbarney matched!

Compare two files and replace

This was one crazy question asked in a quiz in one of the competitions in the place where I work:
They wanted this to be solved using perl only and ASAP. So I came up with a one liner.

File1
Hello HELLO
world WORLD
good GOOD
File2
Hello all this is just
a text file to demonstrate
some good programming. Welcome
to the world of programming.

Now the words of the first column of the first file,if they are present in the second file then they
should be replaced with what ever is there in the second column of the first file.

So the output would look like:

HELLO all this is just
a text file to demonstrate
some GOOD programming. Welcome
to the WORLD of programming.

Below is the solution that i wrote in perl:

perl -F -lane 'BEGIN{$count=0;$flag=0}
               if($flag==1)
               {$count=1}
               $X{$F[0]}=$F[1];
               if(eof && $count!=1)
               {foreach(%X){$H{$_}=$X{$_}};
               $flag=1}
               foreach(@F){if(exists($H{$_})){$_=$H{$_};}}
               if($count!=0){print "@F"}' 
               File1 File2

Print lines between two patterns in a file

I faced this requirement  where I needed to delete some lines from a file based on two patterns(start and end)for which I thought I would use perl:
1 text 
2 start
3 to be deleted
4 to be deleted
5 text to be deleted      
6 to be deleted          
7 end -should be included
8 text 
9 start
10 text to be deleted
11 end -should be included
12 text

below is the script to achieve this:


#!/usr/bin/perl

use strict;
use warnings;

my $num_to_del;
my @data;
my $to_pr=1;

sub create_files() {

        open(MYFILE, 'joinl.txt');
        while (<MYFILE>) {
if(/start/){
  $to_pr=0;
  }
if(/end/){
         $to_pr=1;
}
         if(defined $to_pr && $to_pr>=1){
print $_;   
}
       }
close(MYFILE);
    }
create_files;

Using Perl File::Find

Unix find command can be used as below for finding all the directory names from the current directort
find . -type d
Here I would like to present an example for doing the same in perl using the module File::Find. This prints all the directory names in the current directory excluding the current directory using perl:

#!/usr/bin/perl
use strict;
use warnings;

use File::Find;

find(\&print_name_if_dir, ".");

sub print_name_if_dir
{
print "$_"."\n" if -d && $_!~/^[\s]*\.[\s]*$/;
}

Executing Sql query in a Perl script

Below is the example. Here we can execute a sql query or a sybase query in a perl script. Please also note that I am not utilizing the DBI module provided by perl.
#!/usr/bin/perl
use strict;
use warnings;

my $result = qx { isql -Uxx -Pxxxxxxx -Dxxxx <<EOF
set nocount on
select count(*) from XXX
go
exit
EOF
};
print $result;
Above example show connecting to the sybase database. If you are using Oracle DB, then you can change the connection string:
isql -Uxx -Pxxxxxxx -Dxxxx

to
sqlplus....
Note:
One strange thing over here never add spaces at the begining of the line after the statement isql.....<<EOF
the query will not be executed in such case you will go nuts trying to figure out why!

Compare two files in Perl

I have 2 files, namely a.txt and b.txt. My task is to search all the strings of a.txt in b.txt. And if I have any match between the strings of a.txt and b.txt, then I want to print the line corresponding to that string and its next line from the file b.txt.
use strict;
use warnings;
my $line1;
my $line2;
my $fh;
my $fh1;
open $fh, "<", "b.txt" or die $!;
open $fh1, "<", "a.txt" or die $!;
my @b = <$fh>;
my @a = <$fh1>;
for (@b)
{
   $line1 = $_;
       for (@a)
       {
       $line2 = $_;
         if ($line1 =~ /^$line2$/)
         {
          print $line2 . " - is match\n";
         }
       }
}
exit;