Insert new line between two lines with perl [closed] - perl

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I want to insert line beetwen line 2 and line 3 that contain concatenate string from this lines
abc
abcd:
abc
abcd
Output:
abc
abcd:
abcd: abcd
abc
abcd

You want to add something after a line that ends with a colon, or after line 2?
If after line 2, you can split("\n", $string) to get an array of lines, splice the new line into the array in position 2, and then join("\n", #array) to get the string back.
If after the line ending in the colon, you can use a regex: s/(:\n)/\1YOUR_NEW_LINE_HERE\n/.

Since you don't specify what you want to put after each line that ends with a colon, I've created a table to stand for some generic decision-making and somewhat flexible handling.
# create a table
my %insert_after
= ( abcd => "abcd: abcd\n"
, defg => "defg: hijk\n"
);
# create a list of keys longest first, and then lexicographic
my $regs
= '^('
. join( '|', sort { length $b <=> length $a or $a cmp $b }
keys %insert_after
)
. '):$'
;
my $regex = qr/$regs/;
# process lines.
while ( <> ) {
m/$regex/ and $_ .= $insert_after{ $1 } // '';
print;
}
"Inserting" a line after the current one is as easy as appending that text to the current one and outputting it.

perl -p -i.bck -e "if ($last ne ''){ $_=~s/.*/$last $&\\n$&/; $last=''} elsif (/:/) {$last = $_;chomp($last);} else {$last = '';}" test
test is the file in question

Related

How to get the first row of every data record using perl? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
Data Record looks like this:
1aaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
__Data__
1bbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbb
__Data__
1ccccccccccccccc
cccccccccccccccc
cccccccccccccccc
Perl code:
$/="__Data__";
open READFILE,"<","a_test.txt" or die "Unable to open file $file";
while(<READFILE>)
{
if(/^([^\n]*)\n([^\n]*)\n/sm)
{
print "$1\n";
}
}
close(READFILE);
This code only outputs 1aaaaaaaaaaaa and not the other first line of the other records. I'm sure there are other ways of doing this but using this code format, how can I get the other records to display only their first line. The ideal results would be:
1aaaaaaaaaaaaaa
1bbbbbbbbbbbbbb
1cccccccccccccc
In one line:
$ perl -nle 'print; $_=<> until /^__Data__/ or eof' input.txt
You could change your regex to output desired content,
if (/ (.+) /x) { print "$1\n"; }
in each record this will match first line as you described above.
Even though it's tempting to process the file section-by-section, in this case it seems more clear-cut to go line-by-line -- because the desired output is line-oriented. This avoids the need to parse the sections.
my $marker = "__Data__\n";
my $flag = 1;
while (my $line = <>){
print $line if $flag;
$flag = $line eq $marker;
}
One solution is to remove leading withespace, split in newline character and print first element, like:
while(<READFILE>)
{
s/\A\s*//;
printf qq|%s\n|, (split /\n/)[0];
}
I will repeat an idea that I've said many times here: A line is only one implementation of the record concept. It is the default implementation, but it is not the only one.
Set the record separator to "\n__Data__\n"
Simply print all the non-newline characters pulled from a regex:
use English qw<$RS>;
local $RS = "\n__Data__\n";
while ( <> ) { # A generic read
print /(.*)/, "\n";
}
Thus, you split the data up by records, delimited by __Data__ and pull out only the first line.

how to reverse a hash in perl without using built in function? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
1) %hash = (
1 => 'a',
4 => 'g',
7 => 'h'
);
WAP to reverse of the given hash without using reverse function?
You should really learn Perl - it is really fun when you learn it yourself.
It is really that simple:
my %rev;
foreach my $key (keys %hash) {
$rev{$hash{$key}} = $key;
}
TIMTOWTDI:
my %a = ( foo => 1, bar => 2 ); # original hash
my #a = %a; # copy to array
my #rev; # reversed list container
push #rev, pop #a while #a; # fill #rev from the back forward
my %rev = #rev; # assign reversed list to hash
my %by_letter;
#by_letter{ values(%by_num) } = keys(%by_num);
or
my %by_letter = map { $by_num{$_} => $_ } keys(%by_num);

Can i randomize parameters with Perl [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
is there a way with Perl to randomize all parameters for example :
http://s.example.com/x?list=hahaha&a=&b=&c=&1
so all parameters with &a=&b=&c=&1 etc.etc.etc.
this is the output i expect?
for (1..10){
#random this http://s.example.com/x?list=hahaha&a=&b=&c=&1
#to be like this
print "\n";
#http://s.example.com/x?list=hahaha&b=&a=&c=&1
#http://s.example.com/x?list=hahaha&c=&a=&b=&1
##http://s.example.com/x?list=hahaha&1=&b=&1=&c
}
So could anyone help with this??
Thnx allready
You provided not that much information, but here's a (very simple) approach that should get you started.
Code
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use URI;
use URI::QueryParam;
# prepare
my #all = map {chr $_} 32 .. 126;
my #word = grep /\w/ => #all;
# randomization helpers
sub rand_number { 1 + rand 10 }
sub rand_param_name { join '' => map {$word[rand #word]} 1 .. rand_number }
sub rand_param_value { join '' => map {$all[rand #all]} 1 .. rand_number }
# create three uris with randomized parameters
for (1 .. 3) {
# prepare
my $uri = URI->new('http://s.example.com/x');
# add randomized parameters
$uri->query_param(rand_param_name() => rand_param_value)
for 1 .. rand_number;
# done
say $uri;
}
Output
http://s.example.com/x?TC10=MX3+B_i!
http://s.example.com/x?BaXgf=%26%7BY%5Dxt%25o&l0f=HM%5Cd%24JB%3E)&lDQ7a94=Xh%3AB3N1jK_&dzGNz3=Y8NX4o9%5BS&YnCMxDdTew=J%5B%7B~b%23&Mr8UpMhPo=H&8_nAwh8ZHe=9%5DRY%40V&EgheAy='Uk&gmqTwKW=7PyitIn&3=V%5EKApdS%2C
http://s.example.com/x?dBA7WswJ5=GX-x&yKHeb=1y1sq%3EjPt&7G=7oa%24XF%7C)jQ&FjVo5IpF=%3BZ%5C&JB7OLer=%7C55&bYo64Fiy=L%23%40&ZhSohJVZ=-W+Rp5c+%5DD&aP=zJP%7Bu&pE5URXCWq=PHZJ%60%3D97L&6Xw7Da7=.Drb

How to print lines from a file that have repeated more than six times [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have a file containing the data shown below. The first comma-delimited field may be repeated any number of times, and I want to print only the lines after the sixth repetition of any value of this field
For example, there are eight fields with 1111111 as the first field, and I want to print only the seventh and eighth of these records
Input file:
1111111,aaaaaaaa,14
1111111,bbbbbbbb,14
1111111,cccccccc,14
1111111,dddddddd,14
1111111,eeeeeeee,14
1111111,ffffffff,14
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,aaaaaaaa,14
2222222,bbbbbbbb,14
2222222,cccccccc,14
2222222,dddddddd,14
2222222,eeeeeeee,14
2222222,ffffffff,14
2222222,gggggggg,14
3333333,aaaaaaaa,14
3333333,bbbbbbbb,14
3333333,cccccccc,14
3333333,dddddddd,14
3333333,eeeeeeee,14
3333333,ffffffff,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
Output:
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
What I have tried is to transponse the 2nd and 3rd fields with respect to 1st, so that I can use nawk on the field of $7 or $8
#!/usr/bin/ksh awk -F"," '{ a[$1]; b[$1]=b[$1]","$2 c[$1]=c[$1]","$3} END{ for(i in a){ print i","b[i]","c[i]} } ' file > output.txt
If your records are unordered
i.e. you may have "1111111" items distributed randomly throughout your input:
$ awk -F, '++a[$1] > 6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
How does this work?
As you know, awk's -F option sets the delimiter. If it's not a special character, there's no pressing need to quote it.
Awk scripts consist of a series of blocks of condition { action; }. If the condition is missing, action is applied to every line. If the action is missing, it is implied to be print;. So an awk script that consists of simply a condition will print every input line for which that condition evaluates to true.
In this case, our condition also has elements of an action. That it, it increments elements of an associative array where the keys are your first field. The increment happens regardless of whether the condition evaluates to true. Also, putting ++ ahead rather than following the variable causes the increment to happen before the evaluation rather than after it. (I'm talking about the difference between ++var and var++.) And if the resultant incremented array element is greater than 6, the condition evaluates to true, causing the line to print.
This is functionally equivalent to the perl solutions in other answers, but because of the nature awk scripts is even tighter and (arguably) simpler. And of course, it's likely to be faster. (In my informal test just now, the awk script above executed more than twice as fast as an equivalent perl script from another answer, processing 250000 lines of input in 0.23s of user time vs 0.61 seconds in perl.)
If your records are ordered
i.e. all your "1111111" lines are together:
$ awk -F, '$1!=f{c=0;f=$1} ++c>6' input.txt
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
How does this work?
If we're on a different $1 than last time (which is also true on the first line), we reset our counter and save $1 to a variable for future comparisons.
Then we increment the counter and print the line (implicitly) if the counter goes above 6.
This has the advantage of not eating memory with an array, but is only appropriate if your goal is to match sequential sets of lines with common $1 rather than handle matching lines that may be randomly distributed throughout your input.
$ perl -F',' -ane 'print unless $seen{ $F[0] }++ < 6' file.txt
Explanation
-a enables autosplit mode, -F',' specifies ',' as the split token, resultant list stored in #F as a result
-n enables implicit line-by-line looping
-e executes following argument ('...' in this case) as Perl code
%seen keeps track of how many times the first field has been seen
Assuming the dots in your data should be commas, this Perl command will do what you ask
perl -aF, -ne 'print if ++$n{$F[0]} > 6' myfile
output
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
With awk (filter.awk):
BEGIN { FS = "[,.]" }
o == $1 { cnt++ }
o != $1 { o=$1; cnt = 0; }
cnt >= 6 { print $0 }
To use:
awk -f filter.awk input_file
If you want to specifically have the awk solution then its here below:
awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' file
tested below:
> awk -F, '{if(seen==$1){count++;}else{seen=$1;count=1}if(count>6)print }' temp
1111111,gggggggg,14
1111111,hhhhhhhh,14
2222222,gggggggg,14
3333333,gggggggg,14
3333333,hhhhhhhh,14
If you need a perl script fo rthis then see below:
#!/usr/bin/perl
use strict;
use warnings;
my $count=0;
my $prev="";
open (MYFILE, 'temp');
while (<MYFILE>) {
my #a=split(/,/);
if($prev==$a[0])
{
$count++;
if($count>6)
{
print "$_";
}
}
else
{
$prev=$a[0];
$count=1;
}
}
close (MYFILE);

What do Perl's grep and map do? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
What does this code actually do?
#array = ( 'hai','hello','bar','foo' ) ;
print grep (/hai/ , #array );
print grep ("hai",#array ) ;
print map (/hai/ , #array );
print map ("hai",#array ) ;
It invokes the map and grep functions. A description of which can be found in the perlfunc entries for grep and map.
Is Google broken today?
Try it out...
print grep (/hai/ , #array );
hai
# writes all elements from #array containing 'hai' in them
print grep ("hai",#array ) ;
haihellobarfoo
# writes all elements, because "hai" evaluates to true
print map (/hai/ , #array );
1
# writes 1 for the only element from the #array, that contains 'hai'
print map ("hai",#array ) ;
haihaihaihai
# maps 'hai' to each element from #array