How can I limit this term to a 3 piece hit? - regex

It would be the real task to sadfsadf! Ghfgh% fgh65 %% of this text to replace the first 3 characters that are true for regexp, so replace it with 'o' sadfsadfoghfghofgh65o%
#!/usr/bin/perl -w
#list=<>;
chomp(#list);
foreach(#list) {
if($_ =~ m/\W/) {
# here is the problem because all the characters you find it
# overwrite it, but I only need to translate 3 characters from it
$_ =~ s/\W/o/g;
print $_."\n";
}
else {
print "->\n";
}
}
#start string => sadfsadf!ghfgh%fgh65%%
#result my program => sadfsadfoghfghofgh65oo
#and I need it => sadfsadfoghfghofgh65o%
change only the first 3 results to 'o'

Here is a way to go:
use feature 'say';
my $in = 'sadfsadf!ghfgh%fgh65%%';
$in =~ s/\W/o/ for 1..3;
say $in;
Output:
sadfsadfoghfghofgh65o%

Solved the problem
Code:
#!/usr/bin/perl -w
while ($be=<STDIN>)
{
chomp $be;
push (#list, $be);
}
foreach $a (#list)
{
$count=0;
if ($a=~/\W/)
{
while (($a=~m/\W/g) && ($count < 3))
{
$count++;
$a=~s/\W/o/;
}
print "$a\n";
}
else {print "->\n";}
}

your data in 'list' file
perl -pe 'for $i(1..3){s/\W/o/} ' list
on bash if you put data such list='sadfsadf!ghfgh%fgh65%%'
for((i=1;i<=3;i++)){ list=`echo $list|sed -E "s/\W/Y/"`; }

Related

Printing both the matched line and lines ±1 upon regex match (1-liner)

How can I print a matched line as well as a line before and after it? I've currently got:
perl -lane 'print if $F[3] > 100000 && $F[2] =~ /^C$/ && print $last; $last = $_'
Which is capable of printing both the matched line and a line before it - but I am not sure how to include the line after.
You can read the next line from the file directly using scalar <>:
perl -lane 'print, print scalar <>
if $F[3] > 100000 && $F[2] =~ /^C$/
&& print $last;
$last = $_' input
Or use a sliding window for overlapping matches:
perl -ane 'BEGIN { #b = map [], 1 .. 3 }
sub out {
shift #b;
if ($b[1][3] > 100_000 && $b[1][2] =~ /^C$/) {
print for map $_->[-1], #b;
}
}
push #b, [#F, $_];
out()
}{ out() # Process the last line
' input
The following handles overlapping matches. $N is the number of lines to printe before and after the matching lines.
perl -lane'
BEGIN { $N = 1 }
if ($F[3] > 100000 && $F[2] =~ /^C$/) { print for splice(#buf), $_; $next=$N }
elsif ($next) { --$next; print }
else { push #buf, $_; splice #buf, 0, -$N }
'
Since we know $N = 1, we can simplify the above into the following:
perl -lane'
if ($F[3] > 100000 && $F[2] =~ /^C$/) { print for splice(#buf), $_; $next=1 }
elsif ($next) { $next=0; print }
else { #buf = $_ }
'
You can also use seek and tell and rewind back one line for overlapping matches:
#!/usr/bin/perl
use strict;
use warnings;
open my $fh ,'<', 'input' or die "unable to open file: $!\n";
my $last="";
while(<$fh>){
my #b=split;
if(($b[3] > 100000) && ($b[2] =~ /^C$/)){
print $last if $last;
print;
my $t=tell $fh;
print scalar <$fh>,"\n";
seek $fh,$t,0; #rewind
}
$last=$_;
}
close($fh);

Find n occurrences from group of characters

Given a string, I am suppose to print "two" if i find exactly two characters from the group xyz.
Given jxyl print two
Given jxyzl print nothing
Given jxxl print two
I am very new to perl so this is my approach.
my $word = "jxyl";
#char = split //, $word;
my $size = $#char;
for ( $i = 0; $i < $size - 1; $i++ ) {
if ( $char[i] eq "x" || $char[i] eq "y" || $char eq "z" ) {
print "two";
}
}
Can anyone tell me why this is isn't working correctly?
From the FAQ:
perldoc -q count
How can I count the number of occurrences of a substring within a string?
use warnings;
use strict;
while (<DATA>) {
chomp;
my $count = () = $_ =~ /[xyz]/g;
print "$_ two\n" if $count == 2;
}
__DATA__
jxyl
jxyzl
jxxl
Outputs:
jxyl two
jxxl two
You basically want to count the number of specific characters in a string.
You can use tr:
#!/usr/bin/perl
use strict;
use warnings;
while (<DATA>) {
chomp;
my $count = $_ =~ tr/xyz//;
print "$_ - $count\n";
}
__DATA__
jxyl
jxyzl
jxxl
Outputs:
jxyl - 2
jxyzl - 3
jxxl - 2
Determining if there are exactly 2 can be done after the counting.
Definitely not the best way to do it, but here is a regex for fun and to show there is more than one way to do things.
perl -e'$word = "jxyl"; print "two" if $word =~ /^[^xyz]*[xyz][^xyz]*[xyz][^xyz]*$/'

Find text enclosed by # and replace the inside

The problem:
Find pieces of text in a file enclosed by # and replace the inside
Input:
#abc# abc #ABC#
cba #cba CBA#
Deisred output:
абц abc АБЦ
cba цба ЦБА
I have the following:
#!/usr/bin/perl
use strict;
use warnings;
use Encode;
my $output;
open FILE,"<", 'test.txt';
while (<FILE>) {
chomp(my #chars = split(//, $_));
for (#chars) {
my #char;
$_ =~ s/a/chr(0x430)/eg;
$_ =~ s/b/chr(0x431)/eg;
$_ =~ s/c/chr(0x446)/eg;
$_ =~ s/d/chr(0x434)/eg;
$_ =~ s/e/chr(0x435)/eg;
$_ =~ s/A/chr(0x410)/eg;
$_ =~ s/B/chr(0x411)/eg;
$_ =~ s/C/chr(0x426)/eg;
push #char, $_;
$output = join "", #char;
print encode("utf-8",$output);}
print "\n";
}
close FILE;
But I'm stuck on how to process further
Thanks for help in advance!
Kluther
Here my solution. (you will fixed it, yes. It is prototype)
for (my $data = <DATA>){
$data=~s/[#]([\s\w]+)[#]/func($1)/ge;
print $data;
# while($data=~m/[#]([\s\w]+)[#]/g){
# print "marked: ",$1,"\n";
# print "position:", pos();
# }
# print "not marked: ";
}
sub func{
#do your magic here ;)
return "<< #_ >>";
}
__DATA__
#abc# abc #ABC# cba #cba CBA#
What happens here?
First, I read data. You can do it yourself.
for (my $data = <DATA>){...}
Next, I need to search your pattern and replace it.
What should I do?
Use substition operator: s/pattern/replace/
But in interesting form:
s/pattern/func($1)/ge
Key g mean Global Search
Key e mean Evaluate
So, I think, that you need to write your own func function ;)
Maybe better to use transliteration operator: tr/listOfSymbolsToBeReplaced/listOfSymbolsThatBePlacedInstead/
With minimal changes to your algorithm you need to keep track of whether you are inside the #marks or not. so add something like this
my $bConvert = 0;
chomp(my #chars = split(//, $_));
for (#chars) {
my $char = $_;
if (/#/) {
$bConvert = ($bConvert + 1) % 2;
next;
}
elsif ($bConvert) {
$char =~ s/a/chr(0x430)/eg;
$char =~ s/b/chr(0x431)/eg;
$char =~ s/c/chr(0x446)/eg;
$char =~ s/d/chr(0x434)/eg;
$char =~ s/e/chr(0x435)/eg;
$char =~ s/A/chr(0x410)/eg;
$char =~ s/B/chr(0x411)/eg;
$char =~ s/C/chr(0x426)/eg;
}
print encode("utf-8",$char);
}
Try this after $output is processed.
$output =~ s/\#//g;
my #split_output = split(//, $output);
$output = "";
my $len = scalar(#split_output) ;
while ($len--) {
$output .= shift(#split_output);
}
print $output;
It can be done with a single regex and no splitting of the string:
use strict;
use warnings;
use Encode;
my %chars = (
a => chr(0x430),
b => chr(0x431),
c => chr(0x446),
d => chr(0x434),
e => chr(0x435),
A => chr(0x410),
B => chr(0x411),
C => chr(0x426),
);
my $regex = '(' . join ('|', keys %chars) . ')';
while (<DATA>) {
1 while ($_ =~ s|\#(?!\s)[^#]*?\K$regex(?=[^#]*(?!\s)\#)|$chars{$1}|eg);
print encode("utf-8",$_);
}
It does require repeated runs of the regex due to the overlapping nature of the matches.

Substitute 2 Non-default lines regular expression in Perl

I'd like to replace the reg expression of "hh:mm:ss" of 2 strings in Perl with "xx:xx:xx" How can I accomplish this?
Code:
use strict;
use warnings;
my $l="12:48:25 - Properties - submitMode : 2";
my $r="54:01:00 - Properties - submitMode : 2";
#my $newLn;
#Find "hh:mm:ss" in $_ :P
if ($l =~ /\d\d:\d\d:\d\d/ || $r=~ /\d\d:\d\d:\d\d/) {
#print "Time found";
s/\d\d:\d\d:\d\d/xx:xx:xx/g; #looking for default $_ , but have $l and $r
s/\d\d:\d\d:\d\d/xx:xx:xx/g;
#substitute with xx: p
print $l,"\n";
print $r,"\n";
} else {
print "No time found found";
}
$l =~ s/\d\d:\d\d:\d\d/xx:xx:xx/g;
$r =~ s/\d\d:\d\d:\d\d/xx:xx:xx/g;
toolic's solution works, but if you want to use the substitution command with the default variable $_, use a foreach loop, like this:
use strict;
use warnings;
my $l="12:04:25 - Properties - submitMode : 2";
my $r="54:01:00 - Properties - submitMode : 2";
#my $newLn;
#Find "hh:mm:ss" in $_ :P
#if ($l =~ /\d\d:\d\d:\d\d/ || $r=~ /\d\d:\d\d:\d\d/) {
for ( $l, $r ) {
s/\d\d:\d\d:\d\d/xx:xx:xx/g ||
do {
print "Not time found in $_\n";
next
};
print $_,"\n";
}

How do I use perl regex to extract the digit value from '[1]'?

My code...
$option = "[1]";
if ($option =~ m/^\[\d\]$/) {print "Activated!"; $str=$1;}
I need a way to drop off the square brackets from $option. $str = $1 does not work for some reason. Please advise.
To get $1 to work you need to capture the value inside the brackets using parentheses, i.e:
if ($option =~ m/^\[(\d)\]$/) {print "Activated!"; $str=$1;}
if ($option =~ m/^\[(\d)\]$/) { print "Activated!"; $str=$1; }
Or
if (my ($str) = $option =~ m/^\[(\d)\]$/) { print "Activated!" }
Or
if (my ($str) = $option =~ /(\d)/) { print "Activated!" }
..and a bunch of others. You forgot to capture your match with ()'s.
EDIT:
if ($option =~ /(?<=^\[)\d(?=\]$)/p && (my $str = ${^MATCH})) { print "Activated!" }
Or
my $str;
if ($option =~ /^\[(\d)(?{$str = $^N})\]$/) { print "Activated!" }
Or
if ($option =~ /^\[(\d)\]$/ && ($str = $+)) { print "Activated!" }
For ${^MATCH}, $^N, and $+, perlvar.
I love these questions : )