Conditional Splitting in Perl - linux

I have the following sentences:
my $sent = 'D. discoideum and D. purpureum developmental programs revealed';
Is there a way I can split the lines so that two consecutive words that have '.' (dot) in between will be treated as one word?
Hence we hope to get this after splitting:
$VAR = ['D. discoideum',
'and',
'D. purpureum',
'developmental',
'programs',
'revealed'];
The standard s/\s+//g will split everything based on space.

Try splitting on:
/(?<!\.)\s+/
This expression matches any space character that does not follow a period, without matching the period itself.

Without a split using a regex:
my #words = $sent =~ /(\S+\.\s+\S+|\S+)/g;

Related

How to remove or replace brackets in a string?

my $book = Spreadsheet::Read->new();
my $book = ReadData
('D:\Profiles\jmahroof\Desktop\Scheduled_Build_Overview.xls');
my $cell = "CD7";
my $n = "1";
my $send = $book->[$n]{$cell};
The above code gets data from a spreadsheet, then prints the content of a cell that I know has text in. It has text of exactly the following format: text(text)
I need to replace the open bracket with a empty space and I need to remove the close bracket. I have tried the below code to substitute the open bracket for an empty space however it does not seem to work.
$send =~ s/(/ /g;
print $send;
The bracket is seen as part of the code, just escape it.
$send =~ s/\(/ /;
print $send;
Since you only replace one char with another, you don't want a substitution, but a transliteration. That's the tr/// function in Perl. Since the pattern is just a list of chars, and not an actual regex, you don't need to escape the open parenthesis (. There is also no /g flag. It just substitutes all occurrences.
$send =~ tr/(/ /;
The main difference to a regular expression substitution is that the transliterations get compiled at compile time, not at run time. That makes the tr/// faster than a s///, especially in a loop.
See the full documentation in perlop.

Perl: Count number of times a word appears in text and print out surrounding words

I want to do two things:
1) count the number of times a given word appears in a text file
2) print out the context of that word
This is the code I am currently using:
my $word_delimiter = qr{
[^[:alnum:][:space:]]*
(?: [[:space:]]+ | -- | , | \. | \t | ^ )
[^[:alnum:]]*
}x;
my $word = "hello";
my $count = 0;
#
# here, a file's contents are loaded into $lines, code not shown
#
$lines =~ s/\R/ /g; # replace all line breaks with blanks (cannot just erase them, because this might connect words that should not be connected)
$lines =~ s/\s+/ /g; # replace all multiple whitespaces (incl. blanks, tabs, newlines) with single blanks
$lines = " ".$lines." "; # add a blank at beginning and end to ensure that first and last word can be found by regex pattern below
while ($lines =~ m/$word_delimiter$word$word_delimiter/g ) {
++$count;
# here, I would like to print the word with some context around it (i.e. a few words before and after it)
}
Three problems:
1) Is my $word_delimiter pattern catching all reasonable characters I can expect to separate words? Of course, I would not want to separate hyphenated words, etc. [Note: I am using UTF-8 throughout but only English and German text; and I understand what reasonably separates a word might be a matter of judgment]
2) When the file to be analzed contains text like "goodbye hello hello goodbye", the counter is incremented only once, because the regex only matches the first occurence of " hello ". After all, the second time it could find "hello", it is not preceeded by another whitespace. Any ideas on how to catch the second occurence, too? Should I maybe somehow reset pos()?
3) How to (reasonably efficiently) print out a few words before and after any matched word?
Thanks!
1. Is my $word_delimiter pattern catching all reasonable characters I can expect to separate words?
Word characters are denoted by the character class \w. It also matches digits and characters from non-roman scripts.
\W represents the negated sense (non-word characters).
\b represents a word boundary and has zero-length.
Using these already available character classes should suffice.
2. Any ideas on how to catch the second occurence, too?
Use zero-length word boundaries.
while ( $lines =~ /\b$word\b/g ) {
++$count;
}

Best way to extract string between underscores using Perl

I have something like:
$string = '/mfsi_rpt/files/mfsi/reports/bval/bval_parlcont_pck_m_20130430.pdf';
I would like to extract the parlcont from the string (the word between the 2nd and 3rd underscore).
What is the best way to achieve this using Perl?
You can match this with a regular expression, by combining greedy and non-greedy matches, and using capturing parenthesis to extract the part you're interested in:
if( $string =~ m:.+/.*?_(.+?)_:) {
print "$1\n";
}
The ".+/" is a greedy match, which will gobble up everything up to the last / to get past the directory components.
Then the ".*?_" is non-greedy, so it will take everything up to the first _
Then "(.+?)_" is another non-greedy to match and capture everything up to the next _
It would be nice if you first take out the filename from the file path using File::Basename then you can use split to take out the desired name.
use strict;
use File::Basename;
my $string = "/mfsi_rpt/files/mfsi/reports/bval/bval_parlcont_pck_m_20130430.pdf";
my $data = ( split( /_/, basename($string) ))[1];
Output:
parlcont

How to split the string and retrieve last two columns in perl

i want to retrive the last two columns of a string
ex
$path = C:\Documents and Settings\ac62599\AC62599_SBI_Release_2012.12.1_int\vob\SBI_src
$path = C:\views\ac62599\AC62599_view\vob\aims
output should be
\vob\SBI_src
\vob\aims
output should come like this . Thanks in advance
Use split to split the paths into directories. You can use a slice to get the last two, then use join to concatenate them back:
for my $path ('C:\Documents and Settings\ac62599\AC62599_SBI_Release_2012.12.1_int\vob\SBI_src',
'C:\views\ac62599\AC62599_view\vob\aims') {
print '\\', join('\\', (split/\\/, $path)[-2, -1]), "\n";
}
A regex seems to be the simplest solution
my ($dir) = $path =~ /((?:\\[^\\]+){2})$/;
Which is to say, look for backslash, followed by one or more non-backslash characters, and look for this sequence twice at the end of the string and capture it.
Note the use of parentheses around the variable is required to give the regex list context.
Output for the sample paths:
\vob\SBI_src
\vob\aims
$string=~m/.*(\\[^\\]*\\[^\\]*)/g;print $1

How to grep/split a word in middle of %% or $$

I have a variable from which I have to grep the which in middle of %% adn the word which starts with $$. I used split it works... but for only some scenarios.
Example:
#!/usr/bin/perl
my $lastline ="%Filters_LN_RESS_DIR%\ARC\Options\Pega\CHF_Vega\$$(1212_GV_DATE_LDN)";
my #lastline_temp = split(/%/,$lastline);
print #lastline_temp;
my #var=split("\\$\\$",$lastline_temp[2]);
print #var;
I get the o/p as expected. But can i get the same using Grep command. I mean I dont want to use the array[2] or array[1]. So that I can replace the values easily.
I don't really see how you can get the output you expect. Because you put your data in "busy" quotes (interpolating, double, ...), it comes out being stored as:
'%Filters_LN_RESS_DIR%ARCOptionsPegaCHF_Vega$01212_GV_DATE_LDN)'
See Quote and Quote-like Operators and perhaps read Interpolation in Perl
Notice that the backslashes are gone. A backslash in interpolating quotes simply means "treat the next character as literal", so you get literal 'A', literal 'O', literal 'P', ....
That '0' is the value of $( (aka $REAL_GROUP_ID) which you unwittingly asked it to interpolate. So there is no sequence '$$' to split on.
Can you get the same using a grep command? It depends on what "the same" is. You save the results in arrays, the purpose of grep is to exclude things from the arrays. You will neither have the arrays, nor the output of the arrays if you use a non-trivial grep: grep {; 1 } #data.
Actually you can get the exact same result with this regular expression, assuming that the single string in #vars is the "result".
m/%([^%]*)$/
Of course, that's no more than
substr( $lastline, rindex( $lastline, '%' ) + 1 );
which can run 8-10 times faster.
First, be very careful in your use of quotes, I'm not sure if you don't mean
'%Filters_LN_RESS_DIR%\ARC\Options\Pega\CHF_Vega\$$(1212_GV_DATE_LDN)'
instead of
"%Filters_LN_RESS_DIR%\ARC\Options\Pega\CHF_Vega\$$(1212_GV_DATE_LDN)"
which might be a different string. For example, if evaluated, "$$" means the variable $PROCESS_ID.
After trying to solve riddles (not sure about that), and quoting your string
my $lastline =
'%Filters_LN_RESS_DIR%\ARC\Options\Pega\CHF_Vega\$$(1212_GV_DATE_LDN)'
differently, I'd use:
my ($w1, $w2) = $lastline =~ m{ % # the % char at the start
([^%]+) # CAPTURE everything until next %
[^(]+ # scan to the first brace
\( # hit the brace
([^)]+) # CAPTURE everything up to closing brace
}x;
print "$w1\n$w2";
to extract your words. Result:
Filters_LN_RESS_DIR
1212_GV_DATE_LDN
But what do you mean by replace the values easily. Which values?
Addendum
Now lets extract the "words" delimited by '\'. Using a simple split:
my #words = split /\\/, # use substr to start split after the first '\\'
substr $lastline, index($lastline,'\\');
you'll get the words between the backslashes if you drop the last entry (which is the $$(..) string):
pop #words; # remove the last element '$$(..)'
print join "\n", #words; # print the other elements
Result:
ARC
Options
Pega
CHF_Vega
Does this work better with grep? Seems to:
my #words = grep /^[^\$%]+$/, split /\\/, $lastline;
and
print join "\n", #words;
also results in:
ARC
Options
Pega
CHF_Vega
Maybe that is what you are after? What do you want to do with these?
Regards
rbo

Resources