일련의 유니코드 문자를 찾기 위해 grep을 사용하는 방법은 무엇입니까?
캐릭터의 예를 봤습니다.유니코드 값으로 문자를 grep하는 방법은 무엇입니까?
쉘 교체 방법 이외의 방법에 관심이 있습니다.
쉘 교체는 약간 제한적인 것처럼 보이기 때문에 예를 들어 \u80 코드 포인트와 같은 그래픽이 아닌 유니코드 문자에서는 작동하지 않는 것 같습니다.
이 방법을 특정 범위 내에서 작동하도록 할 수 있지만 \u80(유니코드 코드 포인트 80)과 같은 비그래픽 문자를 포함하지 않는 지점까지만 가능합니다.
$ echo grep [$'\u41'-$'\u45']
grep [A-E]
$ echo 4142434445|xxd -r -p
ABCDE
$ echo 4142434445|xxd -r -p | grep [$'\u41'-$'\u45']
ABCDE
$ 방법은 쉘 수준에서 대체를 사용하므로 예를 들어 문자를 찾는 데는 작동하지 않습니다 \u0080-\uFFFF
. \u0080
왜냐하면 쉘이 문자를 표시할 수 없으면 작동하지 않기 때문입니다.
ugrep은 데비안의 apt-get을 통해 사용할 수 있지만 VPS의 내 우분투 버전에서는 작동하지 않습니다. 다시 테스트 해봐야 겠습니다.
노트 쉘 교체 방법은 제어 문자에 대해 작동하므로 다양한 제어 문자나 유니코드 문자, 그리고 의심할 바 없이 ugrep도 잘 작동할 것입니다. 처음에 쉘 대체를 위해 grep을 사용하려고 시도했을 때 나도 모르게 잘못된 바이트를 입력했습니다. 예제가 echo 418042| xxd -r -p
보여서 A▒B
이것이 잘 작동한다고 생각하고 grep을 시도하고 있습니다. 그래서 grep에 잘못된 데이터를 전달하고 있습니다. 80은 \u80의 utf-8이 아닙니다. 높은 비트 문자(예: £)의 에코는 UTF-8을 출력하고 있음을 명확하게 나타냅니다. £를 echo £ | xxd -p
표시하는 c2a3은 c2a30a
utf-8입니다. 올바른 바이트를 입력하면 작동합니다. 예를 들어 c280
\u80도 echo $'\u80'
작동합니다. 이 페이지는 utf-8과 유니코드 코드 포인트의 매핑을 보여주는 데 적합합니다.https://www.utf8-chartable.de/
쉘 대체가 작동하는 동안 쉘 대체 이외의 작업을 수행하는 답변이 있어서 기쁩니다. 대안이 있으면 좋을 것이기 때문입니다.
답변1
gnu-grep 및 유사 항목에서는 PCRE 옵션을 사용 -P
하고
\x{HHHH}
다음 구문을 사용할 수 있습니다.
$ grep -o -P '[\x{0410}-\x{042F}]+' # same as: grep -o -P '[А-Я]+'
абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕ
=> АБВГДЕ
답변2
GNU 시스템에서는 최소한 문자가 멀티바이트(예: UTF-8, GB18030)에 매핑되는 로케일의 유니코드 코드 포인트와 다른 방식의 바이트 값(ASCII 또는 ISO를 사용하는 로케일)을 기반으로 한 순서를 보장 LC_COLLATE
해야 합니다 C
. 8859-1은 유니코드 코드 포인트 순서와도 일치해야 합니다.
그래서:
LC_COLLATE=C grep $'[\u1111-\uaaaa]'
U+1111과 U+AAAA 사이의 유니코드 코드 포인트가 있는 문자가 하나 이상 포함된 행을 찾아야 합니다(설정에 표시된 로캘의 문자 맵에 따라 인코딩됨 LC_CTYPE
). 달리 설정된 것이 없다고 가정합니다 $LC_ALL
(보다 우선하므로 $LC_COLLATE
).
잘못된 U+D800 - U+DFFF 범위를 넘지 않는 것이 좋습니다. 이 범위의 코드 포인트는 UTF-16 인코딩용으로 예약되어 있으며 유효한 문자에 적합하지 않으며 일부 도구에서 잘못된 문자를 인코딩하는 데 사용되었습니다. U+0001, U+D7FF, U+E000, U+10FFFF 내의 문자를 사용하세요.
또한 범위의 경계가 로케일의 유효한 문자와 일치하는지 확인해야 합니다. $'\uxxxx'
(U+xxxx는 로케일 문자 집합의 문자가 아님) 의 동작은 $'\u...'
이 연산자를 지원하는 셸마다 다릅니다. 일부 쉘( zsh 의 ksh93 포함 $'...'
) $'\u...'
에서는 $'\u...'
UTF-8을 문자 맵으로 사용하는 로케일에서만 작동합니다( 출력 참조 locale charmap
).
답변3
나는 몇몇 Perl 전문가를 인터뷰했습니다. 그리고 일련의 유니코드 문자를 찾기 위해 grep과 동등한 perl oneliner를 얻었습니다.
$ echo £
£
그래서 문자를 숫자로 표현한 서수라는 개념이 있습니다. (무엇이 인코딩인지 코드 포인트인지 추측합니다. 서수라는 단어는 옵션에 따라 인코딩이 될 수 있으므로 \x 뒤에 오는 내용을 설명하는 데 유용하므로 바이트가 저장되거나 유니코드 코드 포인트가 될 수 있습니다. , 바이트이지만 인코딩되지 않음(저장/메모리에 쓰기용)
바이트/옥텟 단위입니다. 다양한 베이스로 표현될 수 있습니다.
%v
printf의 형식 지정자입니다.
$ perl -e 'printf "%vx\n",A'
41
$ perl -e 'printf "%vx\n",4'
34
%vd는 52(문자 "4"의 10진수 표현)입니다. %vx는 16진수 표현입니다.
£의 UTF-8 인코딩은 c2a3입니다. https://www.utf8-chartable.de/
$ echo £ | xxd -p
c2a30a
두 자리 이상의 \x를 사용하는 경우 중괄호를 사용해야 합니다. \엑스{..}
$ echo £ | perl -CIO -ne 'print if /[\x0A]/'
£
$ echo £ | perl -CIO -ne 'print if /[\x{0080}-\x{FFFF}]/'
£
-CIO UTF-8 표현(c2a3)의 서수를 유니코드 코드 포인트 표현(a3)으로 변환합니다. 따라서 \x와 함께 -CIO를 사용할 때 \x 뒤에 오는 내용은 유니코드 코드 포인트 표현이어야 합니다.
다음은 \u0080 이상의 항목과 일치합니다. \uFFFF에서 멈추지 않습니다. 그냥 정규식입니다.
$ echo £ | perl -CIO -ne 'print if /[^\x00-\x7f]/'
£
-CIO를 제거하면 유니코드 코드 포인트 바이트가 아닌 UTF-8 바이트와 일치합니다. -CI가 없으면 UTF-8로 인코딩된 바이트를 유니코드 코드 포인트로 변환/해석/디코딩하지 않습니다.
$ echo £ | perl -ne 'print if /\xc2/'
£
$ echo £ | perl -ne 'print if /\xa3/'
£
그래서 요약하자면
$ echo £ | perl -CIO -ne 'print if /[\x{0080}-\x{FFFF}]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x00-\x7f]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x{00}-\{x7f}]/'
£
$ echo £ | perl -CIO -ne 'print if /[^\x{0000}-\{x007f}]/'
£
perl -CIO
다음에서 녹음됨perldoc perlrun
-C [*number/list*]
The -C flag controls some of the Perl Unicode features.
...
I 1 STDIN is assumed to be in UTF-8
O 2 STDOUT will be in UTF-8
그리고 perldoc perlunicode와 perldoc perlre가 언급되었습니다\x{...}