[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_CTYPEC문자열을 처리하는 각 바이트 인 경우 자신의 자로 ( 아니오 로 부호화 규칙에 기초한 해석이 수행된다) 는 관계없이 대 – 멀티 주문형 – UTF-8 인코딩 OS X는 기본적으로 이용하는 것을 여기서 외국 문자 에는 멀티 바이트 인코딩이 있습니다.

간단히 말해서 : 설정 LC_CTYPEC 원인 기본적인 영어 문자로 문자 (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간에 합법적 인 혼동이있을 수 있으므로 바이트 순서 표시를 앞에 추가해야합니다 ( 유니 코드 표준에서는 권장하지 않더라도 ) . 불행히도 엔디안 ( 또는 ) 을 명시 적으로 지정할 때 바이트 순서 표시를 앞에 두지 않으므로 플랫폼 별 엔디안을 사용 하는 을 사용해야 합니다. 그런 다음 사용 하여 실제 엔디안을 찾습니다 .iconvUTF-16BEUTF-16LEUTF-16file --mime-encodingiconv

( 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. 내 목적을 위해 잘 작동했습니다.