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 쉘에 의존합니다!) 도움이 될 수 있습니다.

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

추가 보너스로 검색은 정규식일 수 있습니다. A 또는 B를 C 또는 D로 바꾸고 싶다고 가정해 보겠습니다.

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

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

관련 정보