Re: RegEx Multi-Line Matching

2005-06-23 Thread John W. Krahn

Jeff Westman wrote:


On 6/20/05, John W. Krahn [EMAIL PROTECTED] wrote:


It looks like you don't really need to use paragraph mode, this should do what
you want:

#!/usr/bin/perl
#
# tnsnames.pl -- reads tnsnames.ora, sorts by host name
use warnings;
use strict;

my $tnsFile = 'tnsnames.ora';
open F, '', $tnsFile or die Could not open file $tnsFile: $!\n;

my ( $host, $name, %tns ) = ( '', '' );
while ( F ) {
   $host = $1 if /\(HOST\s*=\s*(\w+)\)/;
   $name = $1 if /\(SERVICE_NAME\s*=\s*(\w+)\)/;
   if ( length $host and length $name ) {
   print *** RESULT : host= $host, service= $name\n;
   $tns{ $host } = $name;
   ( $host, $name ) = ( '', '' );
   }
   }
close F;

for ( sort keys %tns ) {
   printf %-8s = %s\n, $_, $tns{ $_ };
   }

__END__


Thank you for your post.  I know I could have just done some
top-down scanning for pairs (I like your style, BTW), but it seemed
safer to do multi-line matching, so I am still a bit bothered why I
couldn't get the match to work in all cases (ie, a blank line was
mandatory).

I also had a basic question on the code you sent.  You have:

 $host = $1 if /\(HOST\s*=\s*(\w+)\)/;
 $name = $1 if /\(SERVICE_NAME\s*=\s*(\w+)\)/;

This works and makes sense.  But what if the line is commented?! 
That is, when I modified this and made this:


 $host = $1 if /[^#].*\(HOST\s*=\s*(\w+)\)/;
 $name = $1 if /[^#].*\(SERVICE_NAME\s*=\s*(\w+)\)/;

it SHOULD have worked (I think!).  It still matched a line that should
have been ignored.  What am I doing wrong?!


The problem is that [^#] can match anywhere so in the string
ab#cd(HOST = xyz) it can match at 'a' or 'b' or 'c' or 'd'.

This should work better:

my $para = '';

while ( F ) {

$para  .= $_;

next if $para =~ tr/(// != $para =~ tr/)//;

$para =~ s/#.*//g;  # remove comment lines

if ( $para =~ /\(HOST\s*=\s*(\w+)\).*?\(SERVICE_NAME\s*=\s*(\w+)\)/s ) {

print *** RESULT : host= $1, service= $2\n;

$tns{ $1 } = $2;
}

$para = '';
}


for ( sort keys %tns ) {
   printf %-8s = %s\n, $_, $tns{ $_ };
   }



John
--
use Perl;
program
fulfillment

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Regex Multi-Line Matching

2005-06-22 Thread Jeff Westman
Hey Chris,

I'm not spamming anyone.  I had an error when I sent my email(s) so I
resent it.  Sorry you had to click the mouse an additional time to
'delete'.




Jeff





On 6/20/05, Chris Devers [EMAIL PROTECTED] wrote:
 On Mon, 20 Jun 2005, Jeff Westman wrote:
 
  Any help would be greatly appreciated.
 
 We heard you the first two times.
 
 Please stop spamming the list with the same question.
 
 
 
 --
 Chris Devers


--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




RegEx Multi-Line Matching

2005-06-20 Thread Jeff Westman
Hello Fellow Perlites,

I'm having difficulty parsing a file and could use some help here.
I've attached my code, output file, and sample job run.

Basically, I want to read an Oracle TNS file (tnsnames.ora) and list
the host name and service on that server based on this input file.  A
sample TNS entry is multi-lined and looke like this

mysprdtmp =
 (DESCRIPTION =
   (ADDRESS_LIST =
 (ADDRESS = (PROTOCOL = TCP)(HOST = mxr)(PORT = 1521))
   )
   (CONNECT_DATA =
 (SERVER = DEDICATED)
 (SERVICE_NAME = mysprd01)
   )
 )

So, when the script runs, I would get this at end of job:

mx01 = tmsprd01
mx16 = mystst04
mxp  = mysdev07
mxq  = mystst02
mxr  = mysprd01
s0869u03 = rdmtst06
ux08 = rdmtst03
uxb  = scsdev01

The script generally works fine, but it has a problem when I do not
have a blank line in between these entries.  In other words, if my
input file has

mysbse =
 (DESCRIPTION =
   (ADDRESS_LIST =
 (ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1521))
   )
   (CONNECT_DATA =
 (SERVER = DEDICATED)
 (SERVICE_NAME = mysbse)
   )
 )
oemdev =
 (DESCRIPTION =
   (ADDRESS_LIST =
 (ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1521))
   )
   (CONNECT_DATA =
 (SERVER = DEDICATED)
 (SERVICE_NAME = oemdev)
   )
 )

it should recognize the new TNS listing and give me

mxp  = mysbse
mxp  = oemdev

(along with the others I am parsing).  Again, if I separate the two
with a blank line, it works fine.  But since this is a DBA-owned file,
I cannot do this.

My regex looks like

my $tnsEntry =  'EOF';
   ^
   \s*\w+\s*=\s*
   \s+\(DESCRIPTION\s*=
   \s+\(ADDRESS_LIST\s*=\s*
   
\s+\(ADDRESS\s*=\s*\(PROTOCOL\s*=\s*TCP\)\(HOST\s*=\s*(\w+)\)\(PORT\s*=\s*\d+\)\)
   \s+\)\s*
   \s+\(CONNECT_DATA\s*=\s*
   \s+\(SERVER\s*=\s*\w+\)
   \s+\(SERVICE_NAME\s*=\s*(\w+)\)
 #   \s+\)\s*
 #   \s+\)
   $
EOF


Any help would be appreciated.  I've been at this off and on for
several days.  Note, this is not a production file, but just a
utility script.


Thanks

Jeff


--
perl script follows (tnsnames.pl):
--

#!/usr/bin/perl
#
# tnsnames.pl -- reads tnsnames.ora, sorts by host name


use warnings;
use strict;

my $host;
my $name;
my %tns;
my @sortKeys;
my $key;
my $val;
my $para;
my $matchNbr;

$/ = '';

# problem: tns entries with no line break are not distiquished

my $tnsEntry =  'EOF';
^
\s*\w+\s*=\s*
\s+\(DESCRIPTION\s*=
\s+\(ADDRESS_LIST\s*=\s*

\s+\(ADDRESS\s*=\s*\(PROTOCOL\s*=\s*TCP\)\(HOST\s*=\s*(\w+)\)\(PORT\s*=\s*\d+\)\)
\s+\)\s*
\s+\(CONNECT_DATA\s*=\s*
\s+\(SERVER\s*=\s*\w+\)
\s+\(SERVICE_NAME\s*=\s*(\w+)\)
 #   \s+\)\s*
 #   \s+\)
$
EOF

die ORACLE_HOME is not defined!\n unless (defined($ENV{ORACLE_HOME} ));

my $tnsFile = ./tnsnames.ora;

open(F,  $tnsFile) or die Could not open file $tnsFile: $!\n;

while (chomp($para = F)) {

undef($host);
undef($name);

if ($para =~ m[$tnsEntry]msxo) {
$matchNbr++;
print -x80, \n;
print *** match #$matchNbr : $para\n;
$host = $1;
$name = $2;
print *** RESULT : host= $host, service= $name\n;

if ((defined($host))  (defined($name))) {
$tns{$host} = $name;
}
}

last if eof(F);
}

close(F);

@sortKeys = sort keys(%tns);

foreach (@sortKeys) {
printf %-8s = $tns{$_}\n, $_;
}


--
sample input file follows (tnsnames.ora)
--

# TNSNAMES.ORA Network Configuration File:
/u01/app/oracle/product/9.2.0/network/admin/tnsnames.ora
# Generated by Oracle configuration tools.
#
# history:
# 05/27/04,kk   Added rdmdev02 and scsdev01
# 06/01/04,js   Added rdmtst02 and rdmtst03 per j.jonawski
# 08/08/04,gv   Added mysdev08
# 09/15/04,gv   Added mystst04
# 09/20/04,cd   Added mysdev04

## mxp ###
## Reports server
repserver_mysbse=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1960))
repserver_mysdev01=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1981))
repserver_mysdev02=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1982))
repserver_mysdev03=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1983))
repserver_mysdev04=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1984))
repserver_mysdev05=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1985))
repserver_mysdev06=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1986))
repserver_mysdev07=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1987))
repserver_mysdev08=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1988))
repserver_mysdev04=(ADDRESS = (PROTOCOL = TCP)(HOST = mxp)(PORT = 1989))

## mxr ###
mysprdtmp =
  (DESCRIPTION =

Regex Multi-Line Matching

2005-06-20 Thread Jeff Westman
My problem is simple.  I want to parse an Oracle TNS file, listing
host and the service it provides.

A sample TNS entry is multi-lined and looks like this:

mysprdtmp =
  (DESCRIPTION =
(ADDRESS_LIST =
  (ADDRESS = (PROTOCOL = TCP)(HOST = mxr)(PORT = 1521))
)
(CONNECT_DATA =
  (SERVER = DEDICATED)
  (SERVICE_NAME = mysprd01)
)
  )

The regex I am using to parse this looks like so:

mysprdtmp =
  (DESCRIPTION =
(ADDRESS_LIST =
  (ADDRESS = (PROTOCOL = TCP)(HOST = mxr)(PORT = 1521))
)
(CONNECT_DATA =
  (SERVER = DEDICATED)
  (SERVICE_NAME = mysprd01)
)
  )


My code snippit is like this:

while (chomp($para = F)) {

undef($host);
undef($name);

if ($para =~ m[$tnsEntry]msxo) {

}

The problem is, that this works great, EXCEPT for cases where I do not
have a blank line separating two concatenated TNS entries (I only get
the last one).

Any help would be greatly appreciated.

Thanks

Jeff

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: Regex Multi-Line Matching

2005-06-20 Thread Chris Devers
On Mon, 20 Jun 2005, Jeff Westman wrote:

 Any help would be greatly appreciated.

We heard you the first two times.

Please stop spamming the list with the same question.



-- 
Chris Devers

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response




Re: RegEx Multi-Line Matching

2005-06-20 Thread John W. Krahn

Jeff Westman wrote:

Hello Fellow Perlites,


Hello,


I'm having difficulty parsing a file and could use some help here.
I've attached my code, output file, and sample job run.

Basically, I want to read an Oracle TNS file (tnsnames.ora) and list
the host name and service on that server based on this input file.  A
sample TNS entry is multi-lined and looke like this

[snip]

The script generally works fine, but it has a problem when I do not
have a blank line in between these entries.  In other words, if my
input file has

[snip]

(along with the others I am parsing).  Again, if I separate the two
with a blank line, it works fine.  But since this is a DBA-owned file,
I cannot do this.

[snip]

Any help would be appreciated.  I've been at this off and on for
several days.  Note, this is not a production file, but just a
utility script.


Thank you for providing a working program and data to test it with.

It looks like you don't really need to use paragraph mode, this should do what 
you want:


#!/usr/bin/perl
#
# tnsnames.pl -- reads tnsnames.ora, sorts by host name

use warnings;
use strict;

my $tnsFile = 'tnsnames.ora';

open F, '', $tnsFile or die Could not open file $tnsFile: $!\n;

my ( $host, $name, %tns ) = ( '', '' );

while ( F ) {

$host = $1 if /\(HOST\s*=\s*(\w+)\)/;
$name = $1 if /\(SERVICE_NAME\s*=\s*(\w+)\)/;

if ( length $host and length $name ) {

print *** RESULT : host= $host, service= $name\n;

$tns{ $host } = $name;
( $host, $name ) = ( '', '' );
}
}

close F;

for ( sort keys %tns ) {
printf %-8s = %s\n, $_, $tns{ $_ };
}

__END__



John
--
use Perl;
program
fulfillment

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/ http://learn.perl.org/first-response