Perl 喜欢正则表达式

Perl 喜欢正则表达式

这应该是直截了当的,但我无法弄清楚。如果我想使用 sed 将 A 或 B 替换为 C,代码可能是:

$ echo AAXXAAYYBB | sed 's/[AB]/C/g'
CCXXCCYYCC

这会导致所有 A 和 B 都转换为 C。

我想做的是将“A”替换为两个(或可能更多)变量之一:

输入:

AAXXAAYYBB

代码:

sed 's/A/[BC]/g'

输出(其中 B 或 C 的替换是随机的):

BCXXCBYYBB 

但这段代码只会将 A 更改为...

$ echo AAXXAAYYBB | sed 's/A/[BC]/g'
[BC][BC]XX[BC][BC]YYBB

如果可能的话,我试图在这里避免使用 PERL。有谁知道如何解决这个问题?

答案1

可以更换第一的字符串与以下内容的匹配:

${str/A/...}

并且,可以通过以下方式生成随机(不是加密安全数字)值:

r=(B C)
${r[RANDOM%2]}      

每次变量r都会扩展。

一个完全相同但实现速度更快的操作是使用 AND 来提取值的最后一位:${r[RANDOM&1]}

所以:

#!/bin/bash

str=AAXXAAYYBB
r=(B C)

while [ "${str%"${str#*A}"}" ]; do      # while there is an A to change
    str=${str/A/"${r[RANDOM&1]}"}
done

echo "str=$str"

每次调用时都会生成一个随机结果。

波斯克斯利

#!/bin/sh

str=AAXXAAYYZZAAA

while [ "${str%"${str#*A}"}" ]; do             # while there is an A.
    r=$(od -An -tu1 -N 1 /dev/urandom)         # get one random byte
    r=$((r&1))                                 # Is it even or odd?
    if [ "$r" -eq 0 ]; then s=B; else s=C;fi   # Select B or C 
    str="${str%%A*}${s}${str#*A}"              # Change the string.
done

echo "str=$str"

也许随机字节可以用更简单(但更神秘)的方式读取,大多数时候使用更快的内置 printf:

r=$(printf '%d\n' "'$(head -c1 /dev/urandom)")

答案2

不是 Sed,但避免 Perl:

$ echo AAXXAAYYBB | gawk '
    BEGIN{srand()} 
    {
      n = patsplit($0,a,/A/,s); 
      for(i=1;i<=n;i++) printf("%s%s", rand() < 0.5 ? "B" : "C", s[i]); 
      print ""
    }
  '
CBXXCCYYBB

答案3

一旦我们诉诸脚本,就有很多方法给这只特定的猫剥皮,但这里是我整理的一些东西 - 它可能不太漂亮(并且依赖于 bash shell!),但它可能会帮助你:

#!/bin/bash

TEXT="AAXXAAYYBB"

echo "Start: $TEXT"

# So long as there are un-converted 'A' in the input string...
while [[ "$TEXT" =~ A ]]
do
        # .. convert one 'A' to a random choice of either 'B' or 'C'
        TEXT=$(echo $TEXT | sed -e "s/A/$(((RANDOM%2>0))&&echo B || echo C)/")

        # lets show how we are progressing...
        echo "Progress: $TEXT"
done

# No more 'A' in the input string, we are done:
echo "End: $TEXT"

输出示例:

第一次运行:

Start: AAXXAAYYBB
Progress: BAXXAAYYBB
Progress: BBXXAAYYBB
Progress: BBXXBAYYBB
Progress: BBXXBCYYBB
End: BBXXBCYYBB

第二次运行:

Start: AAXXAAYYBB
Progress: CAXXAAYYBB
Progress: CBXXAAYYBB
Progress: CBXXCAYYBB
Progress: CBXXCBYYBB
End: CBXXCBYYBB

答案4

Perl 喜欢正则表达式

如果您选择使用 perl,您会发现该e标志对于替换很有用。这e会将替换评估为代码。

例如: s/A/c("BC")/eg其中 c 是从字符串中提取随机字符的子例程。

使用 A->[BC] 进行硬编码:

sub c {
  if(my $s = shift) {
    my $index = int(rand(length($s)));
    return substr($s, $index, 1);
  }
}

while(<<>>){
  print s/A/C("BC")/eg
}

或者压缩成一篇不太漂亮的单行诗。 (为了清楚起见,实际上是两行):

perl -E 'sub c {if(my $l = shift) {substr($l, int(rand(length($l))), 1);}}' -plE 's/A/c(BCBBB)/eg'

展开为 random_replace:

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

die "usage: random_replace regex string_of_replacement_chars\n" unless @ARGV == 2;
my $search = shift;
my $replace = shift;

sub c {
  if (my $s = shift) {
    my $index = int(rand(length($s)));
    substr($s, $index, 1);
  }
}

while(<<>>)
{
  s/$search/c($replace)/eg;
  print;
}
% echo "AAAAAA" | ./random_replace A BC
CCCCBC

% echo "AAAAAA" | ./random_replace A BC
BBBBBC

作为额外的好处,搜索可以是正则表达式。假设您想用 C 或 D 替换 A 或 B:

% echo "AAABBB" | ./random_replace '[A-B]' CD
CCCDCD

% echo "AAABBB" | ./random_replace '[A-B]' CD
DDCCDD

相关内容