다음을 다시 작성하는 sed
(또는 또는 둘 다) 작성 방법 :awk
echo 'v100 v201 v102 v300 v301 v500 v999 v301' | sed/awk ...
이 출력에:
v1 v2 v3 v4 v5 v6 v7 v5
즉, 각 후속 항목은 vx
처음부터 다시 작성되며 동일한 항목이 시퀀스에서 사용되는 경우 v1...vn
(즉) 동일한 항목이 적용되어야 합니다.v
v301
v
v5
참고: 예제 입력 시퀀스는 가능한 모든 경우(예: 중복, 순서가 잘못된 원본 데이터, 원본 번호 점프)를 보여줍니다.
이 질문에 답할 수 있는 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
재설정 하고 일련의 숫자만 교체되도록 내용을 왼쪽에 둡니다 .v
K
v
s
- 이
e
플래그를 사용하면 대체가 다음과 같이 처리됩니다.암호평가 하여e
대안을 만들어 보세요. 이 코드에는$&
일치하는 부분을 포함합니다. A // B
형식이다또는A
if가 달리A
정의된 경우 로 확장됩니다 ( if가 다음 으로 확장되는 것과B
반대 ).A || B
A
A
진짜가치 및B
기타).//=
해당 할당 양식입니다.A //= B
의 약어 도 마찬가지다if (defined(A)) {A} else {A = B}
.
$seen
해시 테이블의 인덱스는 다음과 같습니다 .끈이 숫자 등의 값은 v2 v02 v002
서로 다른 문자열인 , 및 를 얻습니다. 위의 예를 대체하여 숫자(010은 8진수 8이 아닌 10으로 처리됨)를 정규화할 수 있습니다. 또는 선행 s를 유지하고 결과를 얻을 수 있습니다.v1 v2 v3
2
02
002
$&
0+$&
v1 v1 v1
s{v0*\K\d+}{$seen{$&} //= ++$n}ge
0
v1 v01 v001
v1
예를 들어 발견된 내용을 바꾸지 않으려면 rev1sion
다음을 추가할 수 있습니다.단어 b
경계\bv\K\d+\b
양쪽 모두와 일치하는 정규식 연산자( )입니다. 또는 공백으로 구분된 단어를 바꾸고( v1.2
예: 단독으로 남겨두기) 일부를 추가하세요.부정적인 시선흰색이 아닌 S
속도의 경우: (?<!\S)v\K\d+(?!\S)
.
답변3
GNU 구현은 이것을 정규식으로 정의하고 특수 변수 에 일치 항목을 기록하는 것을 awk
지원합니다 . 따라서 이를 사용하여 다음을 수행할 수 있습니다.RS
RT
$ 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