Can I Grep multiple lines??

C

Chris L.

Dear All,
I am trying to match a specific pattern using grep.

my @results=grep(/$cominput/,@common);
print "@results";

Naturally,Grep is only printing the lines that variable '$cominput' is
found on. My dilemma is I want to print a pattern. Specifically, where
variable '$cominput' is found all the way until the character '<' is
found. Example,

<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<
I would like to grep from "$cominput" to the character "<".

I have looked into the map function and several pattern matching
examples from google searches, ie:
while (<>) {
if (/BEGIN PATTERN/ .. /END PATTERN/) {
}
}

But nothing seems to be working. is there a better way to accomplish
this??
Thank you very much for your time.
Chris
 
U

usenet

Chris said:
I am trying to match a specific pattern using grep.

I would like to grep from "$cominput" to the character "<".

I have looked into the map function

You need to instead look at how Regular Expressions work (perldoc
perlre), such as (untested):

grep /$cominput.*</ @whatever;
 
U

usenet

grep /$cominput.*</ @whatever;

Waitaminute, that didn't answer the question - sorry. Too late I
noticed the OP specified multiple lines.

I don't believe you can grep over multiple lines, but I'm not certian
of that...
 
E

Eric Schwartz

Just a minor tweak to your regex:

Jim Gibson said:
#!/usr/local/bin/perl
use strict;
use warnings;

local $/;
my $data = <DATA>;
if( $data =~ m/<\$cominput(.*)</s ) {

You probably want:

if( $data =~ m/<\$cominput([^<]*)</s ) {

there instead. Try running both versions against a __DATA__ section
that looks like:

<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<
<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<

and see why. :)

-=Eric
 
I

it_says_BALLS_on_your forehead

Chris said:
Dear All,
I am trying to match a specific pattern using grep.

my @results=grep(/$cominput/,@common);
print "@results";

Naturally,Grep is only printing the lines that variable '$cominput' is
found on. My dilemma is I want to print a pattern. Specifically, where
variable '$cominput' is found all the way until the character '<' is
found. Example,

<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<
I would like to grep from "$cominput" to the character "<".

I have looked into the map function and several pattern matching
examples from google searches, ie:
while (<>) {
if (/BEGIN PATTERN/ .. /END PATTERN/) {
}
}

But nothing seems to be working. is there a better way to accomplish
this??

if i understand your problem correctly, this may work:
while (<>) {
/($cominput[^<]*?)</ && print $1, "\n";
}
 
X

xhoster

Chris L. said:
Dear All,
I am trying to match a specific pattern using grep.

my @results=grep(/$cominput/,@common);
print "@results";

Naturally,Grep is only printing the lines that variable '$cominput' is
found on.

It is returning lines that match the *contents* of variable $cominput when
such contents are interpreted as a regex.

My dilemma is I want to print a pattern. Specifically, where
variable '$cominput' is found all the way until the character '<' is
found. Example,

Then change the definition of a line such that they are terminated by "<"
rather than by "\n".

$/='<';

Xho
 
X

Xicheng

Chris said:
Dear All,
I am trying to match a specific pattern using grep.

my @results=grep(/$cominput/,@common);
print "@results";

Naturally,Grep is only printing the lines that variable '$cominput' is
found on. My dilemma is I want to print a pattern. Specifically, where
variable '$cominput' is found all the way until the character '<' is
found. Example,

<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<
I would like to grep from "$cominput" to the character "<".

I have looked into the map function and several pattern matching
examples from google searches, ie:
while (<>) {
if (/BEGIN PATTERN/ .. /END PATTERN/) {
}
}
If you are working on arrays instead of files, you may try map instead
of grep, coz the later does nothing on your array elements..
===========
use strict; use warnings;
use Data::Dumper;
my @array = (
'sfdsgfdhgdh<$cominput 7894596 isnlpop 78304 plmeitn 4457624
knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523 <dsfgdsg ',
'asdf<< afsef
asefsdfg <$cominput ',
'sfdsgfdhgdh<$cominput dfdsg
111
222 < < ',
'
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523 <dsfgdsg ',
);
print Dumper \@array;
my @tmp = map {/<\$cominput([^<]*)</} @array;
print Dumper \@tmp;
==============
Best,
Xicheng
 
T

Tad McClellan

I don't believe you can grep over multiple lines,


Of course you can.

grep() filters a list.

If the elements of that list contain multiple lines, then grep()
will select on multiple lines.


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

my @list = ("line\n1\n", "line\n2\n");
foreach my $selected ( grep /2/, @list ) {
print ">>>$selected<<<";
}
 
T

Tad McClellan

Chris L. said:
I am trying to match a specific pattern using grep.

my @results=grep(/$cominput/,@common);


What is the value in $cominput?

We must know what the pattern is if we are to help.

What are the values in @common?

We must know what strings the pattern match will be applied
to if we are to help.

print "@results";

Naturally,Grep is only printing the lines that variable '$cominput' is
found on.


From the data that you show below '$cominput' is a _string_
not a variable.

My dilemma is I want to print a pattern.


I doubt that you want to print a pattern.

I expect that yo want to print the part of a string that
matches a pattern.

Specifically, where
variable '$cominput'


You mean the _string_ '$cominput' (I think).

is found all the way until the character '<' is
found. Example,


Then write a pattern that matches all the way until the
character '<' is found.

<$cominput 7894596 isnlpop 78304 plmeitn 4457624 knmljebn
93643456346500 lfnsndh 235 hfgnsdljjtngf 7753 fhs 8694039486 jfsndfkgs
jsdhfnskdk 753299658 hgnsnd 2573275 nvndjgfi 847523
<


Is that really what your data looks like?

I thought you said that grep() was matching something, but grep()
won't match anything with what I assume your pattern is.

I must assume what your pattern is because you have not told
us what your pattern is.

I would like to grep from "$cominput" to the character "<".


You don't need grep() for that.

You need a pattern match for that:

print "$1\n" if $string =~ /(\$cominput[^<]*)/;


Note that the dollar sign is escaped, because I think you
are talking about a literal dollar sign, rather than one that
functions as a sigil on a Perl scalar variable.

But nothing seems to be working.


If you show us what you tried (in a form that allow _us_ to try
it too) then we could help you fix it.

But you didn't, so we can't.

is there a better way to accomplish
this??


A "better way" implies that you have discovered at least one way.

I get the impression that you do not have _any_ ways of accomplishing "this".

Thank you very much for your time.


Your post is so chock full of inconsistencies that loose (incorrect)
terminology that I cannot divine what you want, nor what you have
tried.

I cannot answer your incomprehensible question.

Have you seen the Posting Guidelines that are posted here frequently?
 
J

Joe Smith

Xicheng said:
If you are working on arrays instead of files, you may try map instead
of grep, coz the later does nothing on your array elements..

No, grep does not change array elements.
It's s/// that changes array elements, for both grep and map.
-Joe
 
J

Joe Smith

Tad said:
Of course you can.

We're talking about a pattern that takes multiple lines to match.
grep() filters a list.

If the elements of that list contain multiple lines, then grep()
will select on multiple lines.

But if the pattern you're searching for is spread over several
lines, a simple grep won't match. Using the .. range operator
may return more than is expected.

Here I'm searching for text that is after 'START' and before 'END',
stretching over several lines:

linux% cat test.pl
$string1 = "zero\n it STARTs here\n middle line\n the END line\n done\n";
($match_without_s) = $string1 =~ /START(.*)END/;
($match_with_s) = $string1 =~ /START(.*)END/s;
print "Without s = '$match_without_s'\n";
print "With s = '$match_with_s'\n";
@lines = $string1 =~ /(.*\n)/g;
@match = grep /START(.*)END/, @lines;
@match_s = grep /START(.*)END/s, @lines;
@match__ = grep /START(.*)/ .. /(.*)END/, @lines;
print "Without s = '@match'\n";
print "With s = '@match_s'\n";
print "with .. = '@match__'\n";

linux% perl test.pl
Without s = ''
With s = 's here
middle line
the '
Without s = ''
With s = ''
with .. = ' it STARTs here
middle line
the END line
'

-Joe
 
X

Xicheng

Joe said:
No, grep does not change array elements.
It's s/// that changes array elements, for both grep and map.
-Joe

I guess I didnt make it clear in my original post. here I actually
meant that the elements in grep's return-list do not have differences
with the corresponding element in the original array. but map's do...
that's so-called differences between FILTER and TRANSFER..

the returned list of grep(FILTER) may have different number of elements
from the original array, but the corresponding elements keep the SAME
contents...

the returned list of map(TRANSFER) may have different contents, but
generally the number of element are the same except when map-block or
expressions return *undefined*....

In OP's post, he can surely use "map" to extract data from his array
elements which may contain multiple lines..

For his given multiple-line text-blocks, no need to use (.*) and 's'
modifier, capturing ([^<]*) does all the tricks for him, either they
are already in a single string like array elements, or read by
paragraph-mode, slurp-mode or whatever multiline-modes..

"A..B" expression is not useful for his case, which extracts data by
line-mode...

Xicheng
 
A

Anno Siegel

Xicheng said:
I guess I didnt make it clear in my original post. here I actually
meant that the elements in grep's return-list do not have differences
with the corresponding element in the original array. but map's do...
that's so-called differences between FILTER and TRANSFER..

That distinction gets blurry when the test function in a filter has
the side-effect of changing the list element it's looking at, as
with s///. In that case, the elements that come out of grep may
not have been among those that went in.
the returned list of grep(FILTER) may have different number of elements
from the original array, but the corresponding elements keep the SAME
contents...

Conceptually, yes. Practically, sometimes not.
the returned list of map(TRANSFER) may have different contents, but
generally the number of element are the same except when map-block or
expressions return *undefined*....

Oh no. Undefined values are registered nicely with map. The block
has to return nothing (an empty list) if it doesn't want to contribute
to the result.

[...]
"A..B" expression is not useful for his case, which extracts data by
line-mode...

I'm not sure what that means, but scalar .. can certainly be useful
with grep.

Anno
 
X

Xicheng

Anno said:
That distinction gets blurry when the test function in a filter has
the side-effect of changing the list element it's looking at, as
with s///. In that case, the elements that come out of grep may
not have been among those that went in.


Conceptually, yes. Practically, sometimes not.

yeah, if you count some expressions like s///,tr///, the elements in
the return list may not necessarilly have the same contents as the
corresponing one in the original array.. I didnt notice that, and I
actually have never used those expressions in "grep" before. thanks for
pointing it out to me..:)
Oh no. Undefined values are registered nicely with map. The block
has to return nothing (an empty list) if it doesn't want to contribute
to the result.

This may come from my experience, when I use:

my @tmp = map {/(sth)/} (list);
print Dumper \@tmp;

and when the map condition are controlled by regex and parenthesis
capturings, I noticed that all the elements which donot satisfy the
condition and thus should register *undefined* in @tmp do not show up
in the printing list of "print Dumper \@tmp". so I supposed these
*undefined* elements are automatically filtered out. you may take a
look at the code I posted in this thread where I did use "map" to
filter out some array elements in the printing result....:)
I'm not sure what that means, but scalar .. can certainly be useful
with grep.

I didnot mean to use it in "grep", and I actually meant using "A..B" as
conditional expression to extract data, i.e.

print $sth if /A/../B/;

which reads/writes data by line-mode unless he resets $/.

Best,
Xicheng
 
T

Tad McClellan

Joe Smith said:
We're talking about a pattern that takes multiple lines to match.


Yes, I gathered that much.

But if the pattern you're searching for is spread over several
lines, a simple grep won't match.


Sure it will, if the _list elements_ are spread over several
lines and otherwise match the pattern.

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

my @list = ("line\n1\n", "line\n2\n");
foreach my $selected ( grep /e\n2/, @list ) {
print ">>>$selected<<<";
}
-------------------

($match_with_s) = $string1 =~ /START(.*)END/s;


Whether the pattern needs an m//s modifier or not is independant
of whether grep can "filter over multiple lines".

(and you probably want non-greedy matching there.)

@lines = $string1 =~ /(.*\n)/g;
@match = grep /START(.*)END/, @lines;
@match_s = grep /START(.*)END/s, @lines;
@match__ = grep /START(.*)/ .. /(.*)END/, @lines;


But now the elements of the list do not contain multiple lines,
as in the predicate I gave in my followup.
 
A

Anno Siegel

Xicheng said:
This may come from my experience, when I use:

my @tmp = map {/(sth)/} (list);
print Dumper \@tmp;

and when the map condition are controlled by regex and parenthesis
capturings, I noticed that all the elements which donot satisfy the
condition and thus should register *undefined* in @tmp do not show up
in the printing list of "print Dumper \@tmp". so I supposed these
*undefined* elements are automatically filtered out. you may take a
look at the code I posted in this thread where I did use "map" to
filter out some array elements in the printing result....:)

Well, a regex that doesn't capture anything doesn't return undef, it
returns nothing. The difference is subtle and not always noticeable.
If you assign from a non-match

my ( $x) = 'abc' =~ /(X)/;

$x will become undefined, so it looks like that is what the regex returned.
However, when you write

my @x = 'abc' =~ /(X)/;

you'll notice that the list is empty. Similarly, in scalar context

my $x = ();

and

my $x = ( undef);

are indistinguishable by their result, though fundamentally different.
In list context the difference becomes apparent:

my @x = ();
my @x = ( undef);

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top