[regex] RE 오류 : Mac OS X에서 잘못된 바이트 시퀀스
iOS 로의 크로스 컴파일을 위해 Mac OS X의 Makefile에서 문자열을 바꾸려고합니다. 문자열에는 큰 따옴표가 포함되어 있습니다. 명령은 다음과 같습니다.
sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
그리고 오류는 다음과 같습니다
sed: RE error: illegal byte sequence
큰 따옴표, 쉼표, 대시 및 콜론을 기쁨없이 탈출하려고했습니다. 예를 들면 다음과 같습니다.
sed -i "" 's|\"iphoneos-cross\"\,\"llvm-gcc\:\-O3|\"iphoneos-cross\"\,\"clang\:\-Os|g' Configure
문제를 디버깅하는 데 시간이 많이 걸립니다. 누구든지 sed
잘못된 바이트 시퀀스의 위치를 인쇄하는 방법을 알고 있습니까? 아니면 불법 바이트 시퀀스가 무엇인지 아는 사람이 있습니까?
답변
sed 's/./@/' <<<$'\xfc'
바이트 0xfc
가 유효한 UTF-8 문자가 아니기 때문에 증상을 나타내는 샘플 명령이 실패합니다 .
대조적으로 GNU는 sed
(Linux, macOS에서도 설치 가능)는 오류를보고하지 않고 유효하지 않은 바이트를 전달합니다.
실제 로케일에 대한 지원을 잃어 버리지 않으 려면 이전에 승인 된 답변을 사용하는 것이 옵션 (미국 시스템 인 경우 외국 문자를 다룰 필요가없는 경우에는 괜찮을 수 있습니다).
그러나 동일한 명령 이 단일 명령 에만 임시 로 적용될 수 있습니다 .
LC_ALL=C sed -i "" 's|"iphoneos-cross","llvm-gcc:-O3|"iphoneos-cross","clang:-Os|g' Configure
참고 : 어떤 중요한 것은입니다 효과 LC_CTYPE
의 설정 C
, 그래서 LC_CTYPE=C sed ...
것 일반적으로 경우에도 작동하지만 LC_ALL
(이외로 설정을 될 일 C
)은 개별 우선합니다 LC_*
같은 – 종류 변수를 LC_CTYPE
. 따라서 가장 강력한 방법은을 설정하는 것 LC_ALL
입니다.
다만, (유효) 설정 LC_CTYPE
에 C
문자열을 처리하는 각 바이트 인 경우 자신의 자로 ( 아니오 로 부호화 규칙에 기초한 해석이 수행된다) 는 관계없이 대 – 멀티 주문형 – UTF-8 인코딩 OS X는 기본적으로 이용하는 것을 여기서 외국 문자 에는 멀티 바이트 인코딩이 있습니다.
간단히 말해서 : 설정 LC_CTYPE
에C
원인 기본적인 영어 문자로 문자 (7 비트 ASCII 범위에있는 것)를 인식 할 수있는 쉘 및 유틸리티를, 그래서 외국 문자. 예를 들어 대문자 / 소문자 변환이 실패 하는 문자로 취급되지 않습니다.
다시 말하지만, 와 같은 멀티 바이트 인코딩 문자를 일치 시킬 필요가없고 é
단순히 이러한 문자 를 전달 하려는 경우에는 문제가 없습니다. .
이것이 불충분하거나 원래 오류 의 원인 (문제를 일으킨 입력 바이트 결정 포함) 을 이해하고 필요할 때 인코딩 변환 을 수행 하려면 아래를 읽으 십시오.
문제는 입력 파일의 인코딩이 쉘의 인코딩과 일치하지 않는다는 것입니다.
보다 구체적으로, 입력 파일에는 UTF-8에서 유효하지 않은 방식으로 인코딩 된 문자가 포함되어 있습니다 (@Klas Lindbäck가 주석에 언급 한 바와 같이). 이것이 sed
오류 메시지가에 의해 말하려고하는 것입니다 invalid byte sequence
.
입력 파일은 다음과 같은 단일 바이트 8 비트 인코딩을 사용합니다.ISO-8859-1
“서유럽”언어를 인코딩하는 데 자주 사용되는 사용합니다.
예:
악센트 문자의 à
유니 코드 코드 포인트 0xE0
(224) 는와 동일합니다 ISO-8859-1
. 그러나 UTF-8 인코딩 의 특성으로 인해이 단일 코드 포인트는 2 바이트 로 표시 0xC3 0xA0
되지만 UTF-8 에서는 단일 바이트 를 전달하려는 시도 0xE0
가 유효하지 않습니다 .
여기서 A의 문제점을 보여주는 캐릭터를 사용 voilà
로서 부호화 ISO-8859-1
와 à
같이 표시 한 (AN ANSI-C 인용 배시 문자열 (비아 바이트 $'...'
용도가 있음) \x{e0}
바이트를 작성하기가) :
주의 sed
명령은 단순히 통해 입력을 전달하는 어떤 조합 효과적으로 없지만, 우리가 오류를 자극해야합니다
# -> 'illegal byte sequence': byte 0xE0 is not a valid char.
sed 's/.*/&/' <<<$'voil\x{e0}'
단순히 문제 를 무시 하기 위해 위의 LCTYPE=C
접근 방식을 사용할 수 있습니다.
# No error, bytes are passed through ('á' will render as '?', though).
LC_CTYPE=C sed 's/.*/&/' <<<$'voil\x{e0}'
당신이 할 경우 결정하는 문제의 원인 입력의 일부 , 다음을 시도하십시오
# Convert bytes in the 8-bit range (high bit set) to hex. representation.
# -> 'voil\x{e0}'
iconv -f ASCII --byte-subst='\x{%02x}' <<<$'voil\x{e0}'
출력은 16 비트 형식으로 상위 비트 세트 (7 비트 ASCII 범위를 초과하는 바이트)를 갖는 모든 바이트를 표시합니다. (그러나 정확하게 인코딩 된 UTF-8 멀티 바이트 시퀀스도 포함합니다. UTF-8에서 유효하지 않은 UTF-8 바이트를 구체적으로 식별하려면보다 정교한 접근 방식이 필요합니다.)
요청시 인코딩 변환 수행 :
표준 유틸리티 iconv
를 사용하여 ( -t
) 및 / 또는 ( -f
) 인코딩 을 변환 할 수 있습니다 . iconv -l
지원되는 모든 것을 나열합니다.
예 :
변환 ISO-8859-1
(기반 셸에 적용되는 인코딩 LC_CTYPE
되며, UTF-8
위의 예제에 기본적으로 기반) :
# Converts to UTF-8; output renders correctly as 'voilà'
sed 's/.*/&/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
이 변환을 통해 외래 문자를 올바르게 일치시킬 수 있습니다 .
# Correctly matches 'à' and replaces it with 'ü': -> 'voilü'
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')"
ISO-8859-1
처리 후 입력 BACK을 변환하려면 결과를 다른 iconv
명령으로 파이프하면됩니다 .
sed 's/à/ü/' <<<"$(iconv -f ISO-8859-1 <<<$'voil\x{e0}')" | iconv -t ISO-8859-1
답변
다음 줄을 파일 ~/.bash_profile
이나 ~/.zshrc
파일에 추가하십시오 .
export LC_CTYPE=C
export LANG=C
답변
내 해결 방법은 Perl을 사용하는 것입니다.
find . -type f -print0 | xargs -0 perl -pi -e 's/was/now/g'
답변
mklement0의 대답 은 훌륭하지만 약간의 조정이 있습니다.
bash
사용할 때 명시 적으로 인코딩을 지정하는 것이 좋습니다 iconv
. 또한 바이트 순서 표시 없이 UTF-8과 ASCII간에 합법적 인 혼동이있을 수 있으므로 바이트 순서 표시를 앞에 추가해야합니다 ( 유니 코드 표준에서는 권장하지 않더라도 ) . 불행히도 엔디안 ( 또는 ) 을 명시 적으로 지정할 때 바이트 순서 표시를 앞에 두지 않으므로 플랫폼 별 엔디안을 사용 하는 을 사용해야 합니다. 그런 다음 사용 하여 실제 엔디안을 찾습니다 .iconv
UTF-16BE
UTF-16LE
UTF-16
file --mime-encoding
iconv
( iconv
지원되는 모든 인코딩을 나열 할 때 모두 대문자이기 때문에 모든 인코딩을 iconv -l
대문자로 만듭니다.)
# Find out MY_FILE's encoding
# We'll convert back to this at the end
FILE_ENCODING="$( file --brief --mime-encoding MY_FILE )"
# Find out bash's encoding, with which we should encode
# MY_FILE so sed doesn't fail with
# sed: RE error: illegal byte sequence
BASH_ENCODING="$( locale charmap | tr [:lower:] [:upper:] )"
# Convert to UTF-16 (unknown endianness) so iconv ensures
# we have a byte-order mark
iconv -f "$FILE_ENCODING" -t UTF-16 MY_FILE > MY_FILE.utf16_encoding
# Whether we're using UTF-16BE or UTF-16LE
UTF16_ENCODING="$( file --brief --mime-encoding MY_FILE.utf16_encoding )"
# Now we can use MY_FILE.bash_encoding with sed
iconv -f "$UTF16_ENCODING" -t "$BASH_ENCODING" MY_FILE.utf16_encoding > MY_FILE.bash_encoding
# sed!
sed 's/.*/&/' MY_FILE.bash_encoding > MY_FILE_SEDDED.bash_encoding
# now convert MY_FILE_SEDDED.bash_encoding back to its original encoding
iconv -f "$BASH_ENCODING" -t "$FILE_ENCODING" MY_FILE_SEDDED.bash_encoding > MY_FILE_SEDDED
# Now MY_FILE_SEDDED has been processed by sed, and is in the same encoding as MY_FILE
답변
sed 명령 전에 iconv 명령 을 파이프하면 됩니다. file.txt 입력이있는 Ex :
iconv -f ISO-8859-1 -t UTF8-MAC file.txt | sed ‘s / something / àéèêçùû / g’| …..
-f 옵션은 ‘from’코드 세트이고 -t 옵션은 ‘to’코드 세트 변환입니다.
웹 페이지는 일반적으로 <charset = iso-8859-1 “/>와 같이 소문자를 표시하고 iconv 는 대문자를 사용합니다. iconv -l 명령을 사용하여 시스템 에 iconv 지원 코드 세트 목록이 있습니다.
UTF8-MAC 는 변환을위한 최신 OS Mac 코드 세트입니다.
답변
누구든지 잘못된 바이트 시퀀스의 위치를 인쇄하기 위해 sed를 얻는 방법을 알고 있습니까? 아니면 불법 바이트 시퀀스가 무엇인지 아는 사람이 있습니까?
$ uname -a
Darwin Adams-iMac 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64
tr 을 사용하여 위의 답변에 대한 방법의 일부를 얻었습니다 .
신용 카드 명세서 인 .csv 파일이 있는데 Gnucash로 가져 오려고합니다. 스위스에 거주하고 있으므로 취리히와 같은 단어를 다루어야합니다. Gnucash가 숫자 필드에서 “”를 좋아하지 않는 것으로 의심되면 간단히 모든 것을 대체하기로 결정합니다.
; ;
와
;;
간다 :
$ head -3 Auswertungen.csv | tail -1 | sed -e 's/; ;/;;/g'
sed: RE error: illegal byte sequence
나는 od 를 사용 하여 약간의 빛을 흘렸다.이 od -c 출력의 절반 아래에 374가있다.
$ head -3 Auswertungen.csv | tail -1 | od -c
0000000 1 6 8 7 9 6 1 9 7 1 2 2 ; 5
0000020 4 6 8 8 7 X X X X X X 2 6
0000040 6 0 ; M Y N A M E I S X ; 1
0000060 4 . 0 2 . 2 0 1 9 ; 9 5 5 2 -
0000100 M i t a r b e i t e r r e s t
0000120 Z 374 r i c h
0000140 C H E ; R e s t a u r a n t s ,
0000160 B a r s ; 6 . 2 0 ; C H F ;
0000200 ; C H F ; 6 . 2 0 ; ; 1 5 . 0
0000220 2 . 2 0 1 9 \n
0000227
그런 다음 올바른 바이트 코드가 무엇이든 tr 을 374로 대체 하도록 설득하려고 시도 할 수 있다고 생각했습니다 . 그래서 먼저 간단한 것을 시도했지만 작동하지 않았지만 번거로운 바이트가 어디에 있는지 보여주는 부작용이있었습니다.
$ head -3 Auswertungen.csv | tail -1 | tr . . ; echo
tr: Illegal byte sequence
1687 9619 7122;5468 87XX XXXX 2660;MY NAME ISX;14.02.2019;9552 - Mitarbeiterrest Z
374 자에서 tr bail을 볼 수 있습니다 .
펄을 사용하면이 문제를 피할 수 있습니다
$ head -3 Auswertungen.csv | tail -1 | perl -pne 's/; ;/;;/g'
1687 9619 7122;5468 87XX XXXX 2660;ADAM NEALIS;14.02.2019;9552 - Mitarbeiterrest Z?rich CHE;Restaurants, Bars;6.20;CHF;;CHF;6.20;;15.02.2019
답변
내 해결 방법은 gnu 사용했습니다 sed
. 내 목적을 위해 잘 작동했습니다.