Perlは正規表現が好きです。

Perlは正規表現が好きです。

これは簡単なはずですが、理解できません。 sedを使用してAまたはBをCに置き換えるには、コードは次のようになります。

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

これにより、AとBの両方がCに変換されます。

私が望むのは、「A」を2つ(またはそれ以上)の変数の1つに置き換えることです。

入力する:

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シェルに依存しています!)、役に立ちます。

#!/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

2回目の実行:

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

答え4

Perlは正規表現が好きです。

Perlを使用することを選択した場合は、このeフラグを置き換えるのに役立ちます。これはeコード置換を評価します。

たとえば、 s/A/c("BC")/egcは文字列から任意の文字を抽出するサブルーチンです。

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
}

あるいは、あまりきれいではない1行の詩に圧縮されることもあります。 (明確にするために実際には2行):

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

追加ボーナスで検索は正規表現にすることができます。 A または B を C または D に変更したいとしましょう。

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

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

関連情報