Perl - Replace Every Nth (And Multiples) Occurrences of a Character with Another Character

perl - replace every nth (and multiples) occurrences of a character with another character

Small perl hack to solve the problem. Using the index function to find the commas, modulus to replace the right one, and substr to perform the replacement.

use strict;
use warnings;

while (<>) {
my $x=index($_,",");
my $i = 0;
while ($x != -1) {
$i++;
unless ($i % 3) {
$_ = substr($_,0,$x) ."|". substr($_,$x+1);
}
$x = index($_,",",$x + 1)
}
print;
}

Run with perl script.pl file.csv.

Note: You can place the declaration my $i before the while(<>) loop in order to do a global count, instead of a separate count for each line. Not quite sure I understood your question in that regard.

Replace every nth Occurrence in a Perl Script

Here's another option:

use strict;
use warnings;

my $i = 0;
my $n = 3;

while (<>) {
s/no_access/read/ if !( ++$i % $n );
print;
}

Usage: perl script.pl inFile [>outFile]

The last, optional parameter directs output to a file.

Hope this helps!

Replacing all occurrence after nth occurrence in a line in perl

You can use the perl solution like

perl -pe 's~^(?:[^:]*:){2}(*SKIP)(?!)|:~~g if /^:account_id:/' test.txt

See the online demo and the regex demo.

The ^(?:[^:]*:){2}(*SKIP)(?!)|: regex means:

  • ^(?:[^:]*:){2}(*SKIP)(?!) - match
    • ^ - start of string (here, a line)
    • (?:[^:]*:){2} - two occurrences of any zero or more chars other than a : and then a : char
    • (*SKIP)(?!) - skip the match and go on to search for the next match from the failure position
  • | - or
  • : - match a : char.

And only run the replacement if the current line starts with :account_id: (see if /^:account_id:/').

Or an awk solution like

awk 'BEGIN{OFS=FS=":"} /^:account_id:/ {result="";for (i=1; i<=NF; ++i) { result = result (i > 2 ? $i : $i OFS)}; print result}' test.txt

See this online demo. Details:

  • BEGIN{OFS=FS=":"} - sets the input/output field separator to :
  • /^:account_id:/ - line must start with :account_id:
  • result="" - sets result variable to an empty string
  • for (i=1; i<=NF; ++i) { result = result (i > 2 ? $i : $i OFS)}; print result} - iterates over the fields and if the field number is greater than 2, just append the current field value to result, else, append the value + output field separator; then print the result.

search and replace nth occurence in a file

$. holds line number for current file handle and can be used for given input file like,

perl -i -pe 's/number\s+555/number 666/ if $. == 2' hello.txt

or if number part can be dropped out,

perl -i -pe 's/555/666/ if $. == 2' hello.txt

Perl replace nth substring in a string

This question might be interesting: Perl regex replace count

You might do something like this:

use strict;
use warnings;

my $count = 3;
my $str = "blublublublublu";
$str =~ s/(lu)/--$count == 0 ? "LA":$1/ge;
print $str;

How can I substitute the nth occurrence of a match in a Perl regex?

Or you can do something as this

use strict;
use warnings;

my $string = "'How can I','use' .... 'perl','to process this' 'line'";

my $cont =0;
sub replacen { # auxiliar function: replaces string if incremented counter equals $index
my ($index,$original,$replacement) = @_;
$cont++;
return $cont == $index ? $replacement: $original;
}

#replace the $index n'th match (1-based counting) from $string by $rep
sub replace_quoted {
my ($string, $index,$replacement) = @_;
$cont = 0; # initialize match counter
$string =~ s/'(.*?)'/replacen($index,$1,$replacement)/eg;
return $string;
}

my $result = replace_quoted ( $string, 3 ,"PERL");
print "RESULT: $result\n";

A little ugly the "global" $cont variable, that could be polished, but you get the idea.

Update: a more compact version:

use strict;
my $string = "'How can I','use' .... 'perl','to process this' 'line'";

#replace the $index n'th match (1-based counting) from $string by $replacement
sub replace_quoted {
my ($string, $index,$replacement) = @_;
my $cont = 0; # initialize match counter
$string =~ s/'(.*?)'/$cont++ == $index ? $replacement : $1/eg;
return $string;
}

my $result = replace_quoted ( $string, 3 ,"PERL");
print "RESULT: $result\n";

Regex to find(/replace) multiple instances of character in string

The reason your code doesn't work is that /g doesn't rescan the string after a substitution. It finds all non-overlapping matches of the given regex and then substitutes the replacement part in.

In [abc@def"ghi"jkl'123], there is only a single match (which is the [abc@def" part of the string, with $1 = '[abc@def' and $2 = ''), so only the first " is removed.

After the first match, Perl scans the remaining string (ghi"jkl'123]) for another match, but it doesn't find another [ (or @).


I think the most straightforward solution is to use a nested search/replace operation. The outer match identifies the string within which to substitute, and the inner match does the actual replacement.

In code:

s{ \[ [^\[\]\@]* \@ \K ([^\[\]]*) (?= \] ) }{ $1 =~ tr/a-zA-Z0-9//cdr }xe;

Or to replace each match by X:

s{ \[ [^\[\]\@]* \@ \K ([^\[\]]*) (?= \] ) }{ $1 =~ tr/a-zA-Z0-9/X/cr }xe;

We match a prefix of [, followed by 0 or more characters that are not [ or ] or @, followed by @.

\K is used to mark the virtual beginning of the match (i.e. everything matched so far is not included in the matched string, which simplifies the substitution).

We match and capture 0 or more characters that are not [ or ].

Finally we match a suffix of ] in a look-ahead (so it's not part of the matched string either).

The replacement part is executed as a piece of code, not a string (as indicated by the /e flag). Here we could have used $1 =~ s/[^a-zA-Z0-9]//gr or $1 =~ s/[^a-zA-Z0-9]/X/gr, respectively, but since each inner match is just a single character, it's also possible to use a transliteration.

We return the modified string (as indicated by the /r flag) and use it as the replacement in the outer s operation.

Replace multiple occurrences between two strings

Yes, it's best to use Perl

perl -pe's/xx(.+?)zz/"xx".$1=~s|a|hello|gr."zz"/ge' file.txt

Perl replace every occurrence differently

I was actually trying to do something like this the other day, here's what I came up with

$fasta =~ s/\>[^_]+_([^\/]+)[^\n]+/

sub {

# return random string

}->();

/eg;

the \e modifier interprets the substitution as code, not text. I use an anonymous code ref so that I can return at any point.



Related Topics



Leave a reply



Submit