다음과 같은 텍스트가 있습니다.
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
쉼표로 구분된 값의 순서를 반대로 바꾸면 됩니다.
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
다음과 같이 처리해야 합니다.
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $03, $05, $07, $00
;-------------------
ITINERARY_01F
.BYTE $03, $05, $07, $09, $00
;-------------------
ITINERARY_01G
.BYTE $28, $0D, $00
;-------------------
ITINERARY_01H
.BYTE $28, $0D, $0F, $13, $00
;-------------------
ITINERARY_01I
.BYTE $28, $0D, $0F, $11, $00
;-------------------
ITINERARY_01J
.BYTE $03, $05, $07, $09, $20, $1E, $00
;-------------------
ITINERARY_01K
.BYTE $28, $0D, $0F, $13, $15, $00
;-------------------
ITINERARY_01L
.BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
.BYTE $00
;---------------------
".BYTE" 뒤의 값을 제외하고는 아무것도 변경할 필요가 없습니다. 이 값은 16진수 형식의 역순이어야 하며 "$"를 접두사로 사용합니다... "편집"해서 미안하지만 지금 이걸 봤습니다. 다시 한 번 감사드립니다!
답변1
나는 여기서 이것을 한다 sed
:
sed '/,/!b
s/\( *[^ ]*\)\(.*\)/\2,\n\1/;:t
s/\([^,]*,\)\(\n.*\)/\2\1/;tt
s/\n\(.*\),/\1/' <<\DATA
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
LABEL1
.BYTE 01, 02, 03, 04, 05
.BYTE 01, 02, 03
DATA
산출
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
현재 줄에 쉼표가 있는지 확인합니다. !
쉼표가 없으면 sed
b
스크립트가 종료되고 해당 줄이 자동으로 인쇄됩니다. 만약 라인하다쉼표를 포함하면 sed
다음이 수행됩니다.
s///
먼저 다음을 교체하여 라인을 준비합니다.\( *[^ ]*\)
- 0개 이상의 공백 시퀀스가 처음 발생한 후\1
바로 뒤에 인용된 0개 이상의 공백이 아닌 문자 시퀀스가 나타납니다.\(.*\)
- 온라인상의 다른 모든 내용은 다음과 같이 인용됩니다\2
.- ...그리고
\2,\n\1
- 노트- 이와 같이
\n
오른쪽 대체 필드에 이스케이프 문자를 사용하는s///
것은 완전히 이식 가능하지 않습니다. 이를 지원하지 않는 경우 명령문에서sed
리터럴 줄 바꿈을 대체하여 이를 수행할 수 있습니다 .n
:
이라는 분기/테스트 태그를 정의 합니다t
.- 여전히 작동하지만
sed
s///
대안은 다음과 같습니다.\([^,]*,\)
- 0개 이상의 쉼표가 아닌 문자의 시퀀스그 다음에인용된 단일 쉼표는 다음과 같습니다\1
...\(\n.*\)
\n
- 적어도 하나의 ewline 문자로 시작하고 패턴 공간에 남아 있는 모든 항목/모든 항목이 뒤따르는 시퀀스(\2
... 로 인용)- ...그리고
\2\1
.
- 이전 est
s///
교체가t
성공 하면 est 태그sed
로 다시 분기 하고 다시 시도하세요.:t
- 마지막으로
sed
일부 정리 및 교체:\n\(.*\),
- ewline 문자가 처음으로 나타나고\n
마지막으로 쉼표가 나타나는 경우...\1
- ...그리고 그 사이의 모든 것.
sed
재귀적 대체 와 마찬가지로 \n
ewline 구분 기호는 한 번에 하나의 쉼표로 구분된 필드 뒤로 이동합니다. \n
ewline이 해당 줄의 첫 번째 문자가 되면 교체가 중지됩니다 . l
재귀 교체 프로세스가 진행되는 방식은 다음과 같습니다 .
01, 02, 03, 04, 05,\n .BYTE$
01, 02, 03, 04,\n .BYTE 05,$
01, 02, 03,\n .BYTE 05, 04,$
01, 02,\n .BYTE 05, 04, 03,$
01,\n .BYTE 05, 04, 03, 02,$
\n .BYTE 05, 04, 03, 02, 01,$
초기 준비 교체 후에는 sed
쉼표와 삽입된 줄 문자를 제외하고는 아무것도 구분되지 않습니다 \n
. 그래서어느쉼표로 구분된 값은 잘 작동합니다. 이것은 긴 비트를 실행한 결과입니다.
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
.BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
.BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
.BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
.BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
.BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
.BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
.BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
답변2
문서 revbytes2.awk
:
#!/usr/bin/awk -f
BEGIN {
FS=",? +"
}
NF>2 && match($0,"^ +\.BYTE ") {
printf substr($0,1,RSTART+RLENGTH-1)
for(i=NF;i>3;i--) printf $i", "
print $3
next
}
1
FS=",? +"
awk
다음 공백 .BYTE
과 ,
바이트 사이의 공백 시퀀스를 필드 구분 기호로 인식 합니다 .
각 행에 대해 공백으로 시작하고 그 뒤에 공백이 오는 2개 이상의 필드가 있는 행을 찾고 표현식의 부작용 으로 .BYTE
합계에서 이 접두사의 시작과 길이를 기억합니다 .RSTART
RLENGTH
match(...)
일치하는 항목이 발견되고 2개 이상의 필드가 있는 경우 및를 사용하여 RSTART
원래 줄에서 접두어를 잘라내고 RLENGTH
나머지 필드는 역순으로 인쇄됩니다.
공백과 .BYTE
공백 접두사가 없거나 필드가 2개 이하인 경우 해당 줄은 그대로 인쇄됩니다. 따라서 .BYTE
되돌릴 것이 없기 때문에 1바이트만 정의하는 -line에 대해서도 이 작업이 수행됩니다 .
테스트 실행:
$ diff -u$(wc -l <input) input <(awk -f revbytes2.awk input)
--- input 2014-10-19 06:04:48.280714146 +0200
+++ /dev/fd/63 2014-10-19 22:40:01.385538235 +0200
@@ -1,42 +1,42 @@
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
- .BYTE $03, $05, $07, $00
+ .BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
- .BYTE $03, $05, $07, $09, $00
+ .BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
- .BYTE $28, $0D, $00
+ .BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
- .BYTE $28, $0D, $0F, $13, $00
+ .BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
- .BYTE $28, $0D, $0F, $11, $00
+ .BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
- .BYTE $03, $05, $07, $09, $20, $1E, $00
+ .BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
- .BYTE $28, $0D, $0F, $13, $15, $00
+ .BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
- .BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
+ .BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
비교 mawk
및 gawk
출력:
$ diff <(mawk -f revbytes2.awk input) <(gawk -f revbytes2.awk input)
gawk: revbytes2.awk:5: warning: escape sequence `\.' treated as plain `.'
표준 출력에서는 별 차이가 없는 것 같습니다. 좋아요!
"^ +\056BYTE "
"^ +\.BYTE "
표현식 안에 쓰지 않으면 경고가 사라집니다 match(...)
.
어쩌면 gawk
일반 사용자는 경고를 피하는 더 나은 방법을 알고 있을 수도 있습니다.
답변3
나는 이렇게 할 것이다:
perl -MTie::File -e'
tie @lines,"Tie::File","your_file";
for(@lines){
next unless /,/; # Skip lines with no commas
$csv = /(\s*[^,\s]+,.*)/;
$new_csv = join ",",reverse split /,/,$csv;
s/\Q$csv/$new_csv/;
}'
부인 성명!
파일이 수정됩니다.현장에서. 필요하지 않은 경우 파일의 가상 복사본을 사용하십시오.
원본 파일의 버전은 수정되지 않습니다.
perl -pe'
next unless /,/; # Skip lines with no commas
chomp;
$csv = /(\s*[^,\s]+,.*)/;
$new_csv = join ",",reverse split /,/,$csv;
$new_csv .= "\n"; # The newline removed by chomp
s/\Q$csv/$new_csv/;
' your_file
가설
- 쉼표 주위의 공백은 신경 쓰지 않습니다.
- 첫 번째 CSV 값은
.BYTE
하나 이상의 공백으로 오프셋됩니다. - "역순"이란 숫자 내림차순으로 정렬하는 것이 아니라 파일에서 찾은 순서를 반대로 하는 것을 의미합니다.
입력하다
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $03, $05, $07, $00
;-------------------
ITINERARY_01F
.BYTE $03, $05, $07, $09, $00
;-------------------
ITINERARY_01G
.BYTE $28, $0D, $00
;-------------------
ITINERARY_01H
.BYTE $28, $0D, $0F, $13, $00
;-------------------
ITINERARY_01I
.BYTE $28, $0D, $0F, $11, $00
;-------------------
ITINERARY_01J
.BYTE $03, $05, $07, $09, $20, $1E, $00
;-------------------
ITINERARY_01K
.BYTE $28, $0D, $0F, $13, $15, $00
;-------------------
ITINERARY_01L
.BYTE $03, $05, $07, $09, $20, $1E, $1C, $27
.BYTE $00
;---------------------
산출
ITINERARY_ARRAY_01
.BYTE <ITINERARY_00A
.BYTE <ITINERARY_01A
.BYTE <ITINERARY_02A
.BYTE <ITINERARY_03A
.BYTE <ITINERARY_04A
.BYTE <ITINERARY_05A
.BYTE <ITINERARY_06A
.BYTE <ITINERARY_07A
.BYTE <ITINERARY_08A
.BYTE <ITINERARY_09A
.BYTE <ITINERARY_10A
.BYTE <ITINERARY_11A
.BYTE <ITINERARY_12A
.BYTE <ITINERARY_13A
.BYTE <ITINERARY_14A
;-------------------
ITINERARY_01E
.BYTE $00, $07, $05, $03
;-------------------
ITINERARY_01F
.BYTE $00, $09, $07, $05, $03
;-------------------
ITINERARY_01G
.BYTE $00, $0D, $28
;-------------------
ITINERARY_01H
.BYTE $00, $13, $0F, $0D, $28
;-------------------
ITINERARY_01I
.BYTE $00, $11, $0F, $0D, $28
;-------------------
ITINERARY_01J
.BYTE $00, $1E, $20, $09, $07, $05, $03
;-------------------
ITINERARY_01K
.BYTE $00, $15, $13, $0F, $0D, $28
;-------------------
ITINERARY_01L
.BYTE $27, $1C, $1E, $20, $09, $07, $05, $03
.BYTE $00
;---------------------
답변4
입력에 따라 다음을 사용할 수 있습니다 perl
.
$ perl -MText::Tabs -anle '
BEGIN {$tabstop = 4};
print and next if /^\S/;
@nums = grep { $_ =~ /\d+/ } @F;
map { s/\D//g } @nums;
map { $_ = (pop @nums) . (@nums==0 ? "" : ",")
if $_ =~ /\d+/ } @F;
print expand "\t@F";
' file
LABEL1
.BYTE 05, 04, 03, 02, 01
.BYTE 03, 02, 01
원래 입력이 정렬되었다고 가정합니다. 그렇지 않은 경우 를 @nums = sort { $a <=> $b } grep { $_ =~ /\d+/ } @F;
사용할 수 있습니다 @nums = grep { $_ =~ /\d+/ } @F;
.