Bash: sed 또는 awk 숫자 시퀀스 다시 작성

Bash: sed 또는 awk 숫자 시퀀스 다시 작성

다음을 다시 작성하는 sed(또는 또는 둘 다) 작성 방법 :awk

echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...

이 출력에:

v1 v2 v3 v4 v5 v6 v7 v5

즉, 각 후속 항목은 vx처음부터 다시 작성되며 동일한 항목이 시퀀스에서 사용되는 경우 v1...vn(즉) 동일한 항목이 적용되어야 합니다.vv301vv5

참고: 예제 입력 시퀀스는 가능한 모든 경우(예: 중복, 순서가 잘못된 원본 데이터, 원본 번호 점프)를 보여줍니다.

이 질문에 답할 수 있는 sed 또는 awk 전문가이신가요?

답변1

사용 awk:

awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'

그러면 각 입력 행의 모든 ​​필드를 반복하여 다시 할당합니다. 재할당된 값 v뒤에는 counter 의 다음 값이 옵니다 n. 단, 필드 값이 이전에 확인되지 않은 경우에는 새 값이 이전에 제공된 필드 값과 동일합니다.

마지막 1항목은 수정된 행의 출력을 트리거합니다.

시험:

$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' | awk '{ for (i=1; i<=NF; ++i) $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'
v1 v2 v3 v4 v5 v6 v7 v5

awk정규식과 일치하는 경우에만 필드를 수정하는 대체 명령 ^v[0-9]+$:

awk '{ for (i=1; i<=NF; ++i) if ($i ~ "^v[0-9]+$") $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n) }; 1'

또는 가독성을 위해 여러 줄로 형식을 지정합니다.

awk '
{
    for (i=1; i<=NF; ++i)
        if ($i ~ "^v[0-9]+$")
            $i = (seen[$i] ? seen[$i] : seen[$i] = "v" ++n)
}; 1'

답변2

그리고 perl:

$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
   perl -pe 's{v\K\d+}{$seen{$&} //= ++$n}ge'
v1 v2 v3 v4 v5 v6 v7 v5
  • v\d+일치 항목 v뒤에 하나 이상의 10진수 숫자가 옵니다. 이후 일치하는 부분의 시작을 \K재설정 하고 일련의 숫자만 교체되도록 내용을 왼쪽에 둡니다 .vKvs
  • e플래그를 사용하면 대체가 다음과 같이 처리됩니다.암호평가 하여 e대안을 만들어 보세요. 이 코드에는 $&일치하는 부분을 포함합니다.
  • A // B형식이다또는Aif가 달리 A정의된 경우 로 확장됩니다 ( if가 다음 으로 확장되는 것과 B반대 ).A || BAA진짜가치 및 B기타). //=해당 할당 양식입니다. A //= B의 약어 도 마찬가지다 if (defined(A)) {A} else {A = B}.

$seen해시 테이블의 인덱스는 다음과 같습니다 .이 숫자 등의 값은 v2 v02 v002서로 다른 문자열인 , 및 를 얻습니다. 위의 예를 대체하여 숫자(010은 8진수 8이 아닌 10으로 처리됨)를 정규화할 수 있습니다. 또는 선행 s를 유지하고 결과를 얻을 수 있습니다.v1 v2 v3202002$&0+$&v1 v1 v1s{v0*\K\d+}{$seen{$&} //= ++$n}ge0v1 v01 v001

v1예를 들어 발견된 내용을 바꾸지 않으려면 rev1sion다음을 추가할 수 있습니다.단어 b경계\bv\K\d+\b양쪽 모두와 일치하는 정규식 연산자( )입니다. 또는 공백으로 구분된 단어를 바꾸고( v1.2예: 단독으로 남겨두기) 일부를 추가하세요.부정적인 시선흰색이 아닌 S속도의 경우: (?<!\S)v\K\d+(?!\S).

답변3

GNU 구현은 이것을 정규식으로 정의하고 특수 변수 에 일치 항목을 기록하는 것을 awk지원합니다 . 따라서 이를 사용하여 다음을 수행할 수 있습니다.RSRT

$ echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
   gawk -v RS='v[0-9]+' -v ORS= '
     RT {$0 = $0 "v" (RT in seen ? seen[RT] : seen[RT] = ++n)}1'
v1 v2 v3 v4 v5 v6 v7 v5

이는 v숫자 다음에 나오는 모든 항목을 대체하며, rev1.2단어(예: in 또는 ) 내에 있는 짝수 숫자 도 대체합니다 rev0lution. 그림내 Perl 방법, 숫자가 0으로 채워져 있으면 조정해야 할 수도 있습니다.

답변4

GNU awk에만 해당:

echo 'v100 v201 v102 v300 v301 v500 v999 v301' |
  awk -v RS='[[:space:]]' -F '' '
    $0 {printf "%s", $1 (A[$0]?A[$0]:A[$0]=++i) RT}'
v1 v2 v3 v4 v5 v6 v7 v5

관련 정보