sort
다음과 같은 라인에서 이상하게 행동하는 것 같습니다 .>>b
$ cat test
a
>>b
b
c
>
>>
$ sort test
>
>>
a
b
>>b
c
나는 그 >>b
줄이 출력의 세 번째 줄일 것이라고 예상했는데 sort
다섯 번째 줄입니다. 왜 이런 일이 발생하며 sort
예상되는 결과를 얻을 수 있는 방법이 있습니까 ?
저는 GNU/Linux Ubuntu 16.04를 사용하고 있습니다.
답변1
현대 언어 환경의 정렬 알고리즘은 매우 복잡합니다.
각 캐릭터(실제로는요소 구성여러 문자의 시퀀스로 구성될 수 있습니다(예: Czech ch
).가중치 구성정렬 순서를 결정합니다.
두 문자열을 비교할 때 모든 문자의 첫 번째 가중치가 먼저 사용된 다음 다른 가중치를 사용하여 두 문자열이 첫 번째 가중치와 동일하게 정렬되었는지 확인합니다.
예를 들어, 많은 로케일에서 , e
및 é
는 E
동일합니다.기초적인가중치(동일한 동등 클래스에 속하며 둘 다 일치합니다 [=e=]
).
echo
따라서 예를 들어 , été
및 를 Enter
첫 번째 패스에서 비교할 때 기본 가중치가 동일 e
하고 두 번째 문자가 순서( before before )를 결정합니다.é
E
c
n
t
첫 번째 패스 이후 été
, , 를 비교할 때 Été
동일한 순위가 지정되므로 두 번째 패스에 2차 가중치를 적용합니다. Ete
일반적인 GNU 로케일에서는 라틴어 스크립트 문자의 두 번째 가중치가 악센트의 우선순위를 결정하는 데 사용됩니다(악센트가 없는 것, 그 다음 예음, 악센트가 있는 것, 브레베, 음소거 등). 그런 다음 été
합계를 결정하기 위해 세 번째 가중치를 사용해야 하며 Été
이는 대소문자를 기준으로 합니다(대부분의 로케일에서는 소문자부터 시작). 심지어 체중이 동일하기 때문에 순위가 같은 캐릭터도 있습니다.
이는 인간과 마찬가지로 사전과 같은 방식으로 텍스트를 정렬하는 데 사용됩니다.
사전에서는 공백과 대부분의 구두점도 무시된다는 것을 알 수 있습니다. 예를 들어 de facto
와 debut
사이를 정렬합니다 devoid
. 공백 문자의 첫 번째 가중치는 IGNORE입니다.
/usr/share/i18n/locales/iso14651_t1_common
GNU 시스템에서는 정의된 핵심 데이터 정렬을 찾을 수 있습니다(경로는 배포판에 따라 다를 수 있음). 거기에서 다음을 볼 수 있습니다:
ifdef UPPERCASE_FIRST
<CAP>
else
<MIN>
endif
[...]
ifdef UPPERCASE_FIRST
[...]
<MIN> # 10
[...]
else
[...]
<CAP> # 9
[...]
endif
[...]
order_start <SPECIAL>;forward;backward;forward;forward,position
<U0020> IGNORE;IGNORE;IGNORE;<U0020> # 32 <SP>
[...]
<U003E> IGNORE;IGNORE;IGNORE;<h> # 140 >
[...]
ifdef DIACRIT_FORWARD
order_start <LATIN>;forward;forward;forward;forward,position
else
order_start <LATIN>;forward;backward;forward;forward,position
endif
[...]
<U0065> <e>;<BAS>;<MIN>;IGNORE # 259 e
<U00E9> <e>;<ACA>;<MIN>;IGNORE # 260 é
[...]
<U0045> <e>;<BAS>;<CAP>;IGNORE # 577 E
<U00C9> <e>;<ACA>;<CAP>;IGNORE # 578 É
이것은 우리가 방금 말한 내용을 보여줍니다. 공간과 >
처음 3개의 가중치는 모두 로 설정됩니다 IGNORE
. 처음 3개의 가중치가 동일하게 정렬된 문자열의 경우에만 상대적 순서( >
공백 앞, <h>
지정되지 않은 조합 기호 앞에 나열됨 <U0020>
)가 고려됩니다.
정의된 로케일 UPPERCASE_FIRST
(예 /usr/share/i18n/locales/tr_TR
: )에서는 대문자가 먼저 나타납니다(세 번째 패스에서 ) . DIACRIT_FORWARD
일부 로케일 과 마찬가지로 de_DE
두 번째 패스에서는 발음 구별 부호 의 순서를 반대로 결정할 수 있습니다 .
>
패스 1, 2 , 3 에서도 동일한 정렬을 수행합니다 . 네 번째 항목에서는 빈 문자열이 모든 항목보다 먼저 정렬되므로 먼저 정렬하세요.>>
>
>>
>>b
그 이후에 정렬하십시오. b
처음 3개 패스에서는 동일하게 정렬되었지만 b
네 번째 패스에서는 무시되어 >
크기가 더 크기 때문입니다. c
첫 번째 패스( >
무시 및 이전) b
보다 적습니다 . c
아이디어를 얻으실 수 있습니다.
C
이제 로케일 정의를 보면 . 훨씬 간단합니다. 가중치는 하나만 있으며, U+0000부터 U+10FFFF까지의 코드 포인트 값을 기준으로 합니다. 따라서 SPC
(U+0020)은 >
(U+003E)보다 먼저 정렬되고, (U+003E)는 b
(U+0062)보다 먼저 정렬되고, (U+0063)은 c
(U+0063)보다 먼저 정렬됩니다. 어떤 캐릭터도 간과되지 않습니다.
적어도 GNU libc의 경우 비교 함수( strcoll()
따라서 사용된 공동 )가 포함될 때 sort
C 로케일 정의 파일에 정의된 순서가 무시됩니다 . 의 값에 관계없이 LC_CTYPE
및 는 와 동일 LC_COLLATE=C
합니다 . 비교는 항상 바이트 값을 기준으로 하기 때문에 해당 바이트가 유니코드 코드 포인트가 반대 방향으로 정렬된 문자에 해당하더라도(예: ISO-8859-15의 0xA4 U+20AC EURO SIGN 대 A5 U+00A5 YEN SIGN) 문자 세트) 및 ( 다르게 설정되지 않은 경우)는 동일한 효과를 갖습니다.strcoll()
strcmp()
LC_ALL=C sort
LC_COLLATE=C sort
LC_ALL
답변2
sort(1)
매뉴얼 페이지 에서 :
*** WARNING *** The locale specified by the environment affects sort order. Set
LC_ALL=C to get the traditional sort order that uses native byte values.
따라서 바이트 값으로 정렬하려면 다음을 사용하십시오.
LC_ALL=C sort test
그렇지 않으면 sort
정렬할 수 있는 키가 발견될 때까지 선행 문자가 무시됩니다. 이것이 바로 >>b
와 b
서로 옆에 있는 이유입니다.