애플리케이션에서 정렬 처리

Microsoft Active Directory, Microsoft Exchange 및 Microsoft Access와 같은 일부 애플리케이션은 이름(UTF-16 문자열)으로 인덱싱된 로캘 및 언어 문자열의 정렬 가능한 데이터베이스와 관련 정렬 가중치를 유지 관리합니다.

정렬 은 일반적으로 고유한 로캘의 사용자에게 직관적입니다. 그러나 애플리케이션 개발자에게는 직관적이 아닐 수 있습니다. 이 항목에서는 애플리케이션에서 정렬을 처리하기 위한 고려 사항에 대해 설명합니다. 정렬은 언어 또는 서수(비언어적)일 수 있습니다.

정렬 함수

애플리케이션에서 다양한 정렬 함수를 사용할 수 있습니다.

일반적으로 정렬 함수는 문자열 문자를 문자별로 평가합니다. 그러나 많은 언어에는 전통적인 스페인어의 두 문자 쌍 "CH"와 같은 여러 문자 요소가 있습니다. CompareStringCompareStringEx 는 애플리케이션에서 제공하는 로캘 식별자 또는 이름을 사용하여 여러 문자 요소를 식별합니다. 반면 lstrcmplstrcmpi 는 사용자의 로캘을 사용합니다.

또 다른 예는 유효한 대문자, 제목 대/소문자 및 "GI"의 소문자 형식(각각 "GI, "Gi", "gi")과 같은 많은 두 문자 요소를 포함하는 베트남어입니다. 이러한 양식은 단일 정렬 요소로 처리되고 대/소문자를 무시하면 같음으로 비교됩니다. 그러나 "gI"는 단일 요소로 유효하지 않으므로 CompareString, CompareStringEx, lstrcmplstrcmpi 는 "gI"를 두 개의 개별 요소로 처리합니다.

CompareString, CompareStringEx, lstrcmp, lstrcmpi, LCMapString, LCMapStringEx, FindNLSStringFindNLSStringEx 함수는 모두 기본적으로 "단어 정렬" 기술을 사용합니다. 이 유형의 정렬에서는 하이픈과 아포스트로피를 제외한 모든 문장 부호 및 기타 무수 문자가 영숫자 문자 앞에 옵니다. 하이픈과 아포스트로피는 다른 무수 문자와 다르게 처리되어 "coop" 및 "co-op"과 같은 단어가 정렬된 목록에 함께 유지되도록 합니다.

애플리케이션은 단어 정렬 대신 SORT_STRINGSORT 플래그를 지정하여 정렬 함수에서 "문자열 정렬" 기술을 요청할 수 있습니다. 문자열 정렬은 하이픈과 아포스트로피를 다른 무수 문자처럼 처리합니다. 정렬 시퀀스의 해당 위치는 영숫자 문자 앞에 있습니다.

다음 표에서는 단어 정렬 결과를 문자열 정렬의 결과와 비교합니다.

Word 정렬 문자열 정렬
지위 청구서의
청구서 지위
청구서의 청구서
없습니다 없습니다
캔 트 없습니다
없습니다 캔 트
공동 작업
새 둥지
공동 작업 새 둥지

 

언어적으로 문자열 정렬

CompareStringCompareStringEx 함수는 언어적 같음을 테스트합니다. 애플리케이션은 문자열을 언어적으로 정렬하기 위해 올바른 로캘과 함께 이러한 함수를 사용해야 합니다.

참고

유니코드와의 호환성을 위해 애플리케이션은 CompareStringEx 또는 유니코드 버전의 CompareString을 선호해야 합니다. CompareStringEx를 선호하는 또 다른 이유는 Microsoft가 상호 운용성을 위해 새 로캘에 대한 로캘 식별자 대신 로캘 이름을 사용하도록 마이그레이션하기 때문입니다. Windows Vista 이상에서만 실행되는 모든 애플리케이션은 CompareStringEx를 사용해야 합니다.

 

언어적 같음을 테스트하는 또 다른 방법은 항상 단어 정렬을 사용하는 lstrcmp 또는 lstrcmpi를 사용하는 것입니다. lstrcmpi 함수는 NORM_IGNORECASE 플래그를 사용하여 CompareString을 호출하고 lstrcmp는 해당 플래그 없이 호출합니다. 래퍼 함수 사용에 대한 개요는 문자열을 참조 하세요.

함수는 모든 로캘에 대해 언어적으로 적절한 결과를 검색합니다. 다음 예제와 같이 정렬 동작에서 서로 다른 로캘에 대한 사용자 기대치가 크게 다를 수 있습니다.

  • 많은 로캘은 ae 합자(æ)를 ae 문자와 동일시합니다. 그러나 아이슬란드어(아이슬란드)는 별도의 문자로 간주하고 정렬 순서로 Z 다음에 배치합니다.
  • A 링(Å)은 일반적으로 A와 분음 부호 있는 차이로 정렬됩니다. 그러나 스웨덴어(스웨덴)는 정렬 시퀀스에서 Z 다음에 A 링을 배치합니다.

함수는 유니코드 표준에 정의된 코드 포인트가 동등한 코드 포인트의 문자열과 정식으로 같은지 엄격하게 확인하려고 시도합니다. 예를 들어, 다이어시스(ü)가 있는 소문자 "u"를 나타내는 코드 포인트는 dieresis()와 결합된 소문자 "u"와 카논리식으로 같습니다. 그러나 정식 동등성이 항상 가능한 것은 아닙니다.

Windows 키보드 및 IME(입력 방법 편집기)를 사용하여 입력한 거의 모든 데이터가 유니코드 표준에 정의된 C 정규화 형식을 준수하므로 NLS 유니코드 정규화 함수를 사용하여 다른 플랫폼에서 들어오는 데이터를 변환하면 특히 최신 한글에 대해 티베트어 스크립트 또는 한글 스크립트를 사용하는 로캘에 대해 가장 일관된 결과를 제공합니다. Windows Vista 이상에서 유니코드 정규화 지원에 대한 자세한 내용은 유니코드 정규화를 사용하여 문자열 표현을 참조하세요.

문자열 비교가 사용자의 언어 기본 설정을 따르는 경우(예: 정렬된 ListView 컨트롤에 대한 항목을 정렬할 때) 애플리케이션은 다음 중 하나를 수행할 수 있습니다.

  • 사용자의 로캘을 사용하여 lstrcmp 또는 lstrcmpi 를 호출합니다.
  • CompareString 또는 CompareStringEx를 호출하여 비교에 대한 로캘을 정의하거나, 추가 플래그를 전달하거나, null 문자를 포함하거나, 문자열의 일부와 일치하도록 명시적 길이를 전달합니다.

예를 들어, 검색된 데이터를 미리 정의된 목록 또는 내부 값과 비교할 때 로캘 매개 변수가 LOCALE_INVARIANT 로캘 매개 변수와 함께 CompareString 또는 CompareStringEx를 사용해야 하는 경우와 같이 비교 결과가 로 에 관계없이 일치해야 합니다. CompareString의 경우 mystr이 "INLAP"인 경우에도 다음 호출 중 하나가 일치합니다. 이 경우 현재 로캘이 베트남어인 경우 lstrcmpi 에 대한 로캘에 민감한 호출이 실패합니다.

Windows XP:

int iReturn = CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);

이전 운영 체제에서:

DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
int iReturn = CompareString(lcid, NORM_IGNORECASE, mystr, -1, _T("InLap"), -1);

문자열을 서수로 정렬

서수(비언어적) 정렬의 경우 애플리케이션은 항상 CompareStringOrdinal 함수를 사용해야 합니다.

참고

이 함수는 Windows Vista 이상에서만 사용할 수 있습니다.

 

CompareStringOrdinal 은 두 유니코드 문자열을 비교하여 언어적 같음이 아닌 이진 같음을 테스트합니다. 이러한 비언어적 문자열의 예로는 NTFS 파일 이름, 환경 변수 및 뮤텍스 이름, 명명된 파이프 또는 mailslots가 있습니다. 대/소문자를 구분하지 않는 옵션을 제외하고 이 함수는 이진이 아닌 모든 동등성을 무시합니다. 다른 정렬 함수와 달리 언어 정렬 체계에 가중치가 부여되지 않은 코드 포인트를 포함하여 모든 코드 포인트가 같은지 테스트합니다.

다음 문은 모두 CompareStringOrdinal 에 이진 비교에 적용되지만 CompareString, CompareStringEx, lstrcmp 또는 lstrcmpi에는 적용되지 않습니다.

  • 라틴어 SMALL LETTER A WITH RING ABOVE(U+00e5) 및 LATIN SMALL LETTER A + COMBINING RING ABOVE(U+0061 U+030a)와 같이 유니코드의 정식으로 동등한 시퀀스는 동일하게 표시되더라도 같지 않습니다("å").
  • 라틴 문자 SMALL CAPITAL Y(U+028f) 및 LATIN CAPITAL LETTER Y(U+0059)와 같이 유니코드에서 매우 유사하게 보이고("" 및 "Y") 언어 테이블의 일부 특수한 대/소문자 가중치에 따라 달라지는 것과 같은 유니코드의 문자는 완전히 다른 문자로 간주됩니다. 애플리케이션이 bIgnoreCaseTRUE로 설정하더라도 이러한 문자열은 다른 문자열과 비교됩니다.
  • 제로 WIDTH JOINER(U+200d)와 같이 정의되었지만 언어 정렬 가중치가 없는 코드 포인트는 코드 포인트 가중치가 있는 것으로 처리됩니다.
  • 이후 버전의 유니코드에서 정의되지만 현재 언어 테이블에 가중치가 없는 코드 포인트는 코드 포인트 가중치를 갖는 것으로 처리됩니다.
  • 유니코드에서 정의되지 않은 코드 포인트는 코드 포인트 가중치를 갖는 것으로 처리됩니다.
  • 애플리케이션이 bIgnoreCaseTRUE로 설정하면 함수는 언어 정렬 테이블의 정보 대신 운영 체제 대문자 테이블을 사용하여 대/소문자를 매핑합니다. 따라서 매핑은 로캘과 독립적입니다.

유니코드의 정식으로 동등한 시퀀스와 유니코드의 정식으로 유사한 문자열에 대한 자세한 내용은 유니코드 정규화를 사용하여 문자열을 나타내기를 참조하세요.

코드 포인트 정렬

일부 유니코드 코드 포인트에는 가중치가 없습니다(예: ZERO WIDTH NON JOINER, U+200c). 정렬 함수는 정렬에 가중치가 없으므로 의도적으로 가중치 없는 코드 포인트를 동등한 값으로 평가합니다. Windows Vista 이상에서 애플리케이션은 NLS 문자열 비교 함수, 특히 CompareStringOrdinal을 호출하여 암호 유효성 검사와 같은 리터럴 이진 센스의 모든 코드 포인트를 평가하여 이러한 코드 포인트를 정렬할 수 있습니다. Windows Vista 이전 운영 체제에서 애플리케이션은 C 런타임 함수 strcmp 또는 wcscmp를 사용해야 합니다.

정렬 함수는 애플리케이션이 hlink_NONSPACE 플래그를 지정하는 경우 NON SPACING BREVE, U+0306과 같은 분음 부호를 무시합니다. 마찬가지로 이러한 함수는 hlink_SYMBOLS 플래그가 지정된 경우 EQUALS SIGN, U+003d 등의 기호를 무시합니다. Windows Vista 이상에서 애플리케이션은 리터럴 이진 센스의 분음 부호 및 기호 코드 포인트를 평가하기 위해 CompareStringOrdinal 을 호출합니다. Windows Vista 이전 운영 체제에서 애플리케이션은 strcmp 또는 wcscmp를 사용해야 합니다.

0xFFFF 및 0x058b 같은 일부 코드 포인트는 현재 유니코드에 할당되지 않습니다. 이러한 코드 포인트는 정렬에서 가중치를 받지 않으며 정렬 함수에 전달되어서는 안 됩니다. 애플리케이션은 IsNLSDefinedString을 사용하여 데이터 스트림에서 유니코드가 아닌 코드 포인트를 검색해야 합니다.

참고

IsNLSDefinedString의 결과는 문자가 이후 버전에서 유니코드에 추가되고 이후에 Windows 정렬 테이블에 추가되는 경우 전달된 유니코드 버전에 따라 달라질 수 있습니다. 자세한 내용은 정렬 버전 관리 사용을 참조하세요.

 

숫자를 숫자로 정렬

Windows 7 이상에서 애플리케이션은 SORT_DIGITSASNUMBERS 플래그 를 사용하여 CompareString, CompareStringEx, LCMapString 또는 LCMapStringEx 를 호출할 수 있습니다. 이 플래그는 숫자를 숫자로 처리하는 정렬(예: "10" 앞의 "2")을 지원합니다.

이 플래그의 사용은 다음과 같은 16진수에 적합하지 않습니다.

01AF
1BCD
002A
12FA
AB1C
AB02
AB12

이 경우 "숫자"는 순서대로 정렬되지만, 사용자는 잘못 정렬된 16진수 목록을 인식합니다.

맵 문자열

LCMAP_SORTKEY 지정되지 않은 경우 애플리케이션은 LCMapString 또는 LCMapStringEx 함수를 사용하여 문자열을 매핑합니다. 원본 문자열이 null로 종료되면 매핑된 문자열은 null로 종료됩니다.

대문자와 소문자 간에 변환할 때 함수는 단일 문자가 단일 문자에 매핑되도록 보장하지 않습니다. 예를 들어 LCMAP_LOWERCASE 및 LCMAP_UPPERCASE 플래그는 독일 샤프 S("ß")를 자체에 매핑할 수 있습니다. 또는 LCMAP_UPPERCASE 플래그는 "ß"를 "SS"에 매핑할 수 있으며 LCMAP_LOWERCASE 플래그는 "SS"를 "ß"에 매핑할 수 있습니다. 동작은 NLS 버전에 따라 달라집니다.

대문자와 소문자 간에 변환할 때 함수는 컨텍스트에 민감하지 않습니다. 예를 들어 LCMAP_UPPERCASE 플래그는 그리스어 소문자 시그마("σ")와 그리스어 소문자 최종 시그마("")를 그리스어 대문자 시그마("Σ")에 올바르게 매핑하지만, LCMAP_LOWERCASE 플래그는 항상 "Σ"를 "σ"에 매핑하고 ""에는 매핑하지 않습니다.

기본적으로 함수는 로 매개 변수가 터키어 또는 아제르바이잔을 지정하는 경우에도 소문자 "i"를 대문자 "I"에 매핑합니다. 터키어 또는 아제르바이잔어에 대해 이 동작을 재정의하려면 애플리케이션에서 LCMAP_LINGUISTIC_CASING 지정해야 합니다. 이 플래그가 적절한 로캘로 지정된 경우 "ı"(소문자 점없는 I)는 소문자 형식인 "I"(대문자 점 없는 I) 및 "i"(소문자 점선 I)는 소문자 형식인 "ı"(대문자 점선 I)입니다.

가타카나 문자를 히라가나 문자에 매핑하도록 LCMAP_HIRAGANA 플래그를 지정하고 LCMAP_FULLWIDTH 지정하지 않으면 LCMapString 또는 LCMapStringEx 는 전체 너비 문자만 히라가나에 매핑합니다. 이 경우 히라가나에 대한 매핑 없이 반자 가타카나 문자가 대상 문자열에 로 배치됩니다. 애플리케이션은 반자 가타카나 문자를 히라가나에 매핑하는 LCMAP_FULLWIDTH 지정해야 합니다. 이 제한의 이유는 모든 히라가나 문자가 전체 너비 문자이기 때문입니다.

애플리케이션이 원본 문자열에서 문자를 제거해야 하는 경우 NORM_IGNORESYMBOLS 및 NORM_IGNORENONSPACE 플래그가 설정된 매핑 함수를 호출하고 다른 모든 플래그를 지울 수 있습니다. 애플리케이션이 null로 종료되지 않은 원본 문자열을 사용하여 이 작업을 수행하는 경우 함수가 빈 문자열을 반환하고 오류를 반환하지 않을 수 있습니다.

정렬 키 만들기

애플리케이션이 LCMAP_SORTKEY 지정하면 LCMapString 또는 LCMapStringEx 는 바이트 값의 이진 배열인 정렬 키를 생성합니다. 정렬 키는 true 문자열이 아니며 해당 값은 원본 문자열의 정렬 동작을 나타내지만 의미 있는 표시 값은 아닙니다.

참고

함수는 정렬 키를 생성하는 동안 아랍어 카시다를 무시합니다. 애플리케이션이 함수를 호출하여 아랍어 kashida를 포함하는 문자열에 대한 정렬 키를 만드는 경우 함수는 정렬 키 값을 만들지 않습니다.

 

정렬 키에는 홀수 바이트가 포함될 수 있습니다. LCMAP_BYTEREV 플래그는 짝수 바이트만 역방향으로 설정합니다. 정렬 키의 마지막 바이트(홀수 위치)는 반전되지 않습니다. 종료 0x00 바이트가 홀수 위치 바이트인 경우 정렬 키의 마지막 바이트로 유지됩니다. 종료 0x00 바이트가 짝수 위치 바이트인 경우 앞에 오는 바이트와 위치를 교환합니다.

정렬 키를 생성할 때 함수는 하이픈과 아포스트로피를 다른 문장 부호 기호와 다르게 처리하므로 "coop" 및 "co-op"과 같은 단어가 목록에 함께 유지됩니다. 하이픈 및 아포스트로피 이외의 모든 문장 부호 기호는 영숫자 문자 앞에 정렬됩니다. 애플리케이션은 정렬 함수에 설명된 대로 SORT_STRINGSORT 플래그를 설정하여 이 동작을 변경할 수 있습니다.

memcmp에서 사용되는 경우 정렬 키는 CompareString 또는 CompareStringEx에서 원본 문자열을 사용할 때와 동일한 순서 생성합니다. 정렬 키에 포함된 null 바이트가 있을 수 있으므로 memcmp 함수는 strcmp 대신 사용해야 합니다.

정렬 버전 관리 사용

정렬 테이블에는 해당 버전을 식별하는 두 개의 숫자, 즉 정의된 버전과 NLS 버전이 있습니다. 두 숫자 모두 주 값과 부 값으로 구성된 DWORD 값입니다. 값의 첫 번째 바이트는 예약되고, 다음 두 바이트는 주 버전을 나타내고, 마지막 바이트는 부 버전을 나타냅니다. 16진수 측면에서 패턴은 0xRRMMMMmm입니다. 여기서 R은 예약됨, M은 주 및 m은 부와 같습니다. 예를 들어 부 버전이 4인 주 버전 3은 0x304 표시됩니다.

정의된 버전은 코드 포인트의 레퍼토리를 식별하며 모든 로캘에 대해 동일합니다. 주 버전이 증가하여 기존 코드 포인트의 변경 내용을 나타냅니다. 부 버전이 증가하여 코드 포인트가 추가되었지만 이전에 기존 코드 포인트가 변경되지 않았음을 나타냅니다.

NLS 버전은 로캘 식별자 또는 로캘 이름과 관련이 있으며 영향을 받는 로캘의 코드 포인트 가중치 변경 내용을 추적합니다. 이미 정렬 가능한 코드 포인트에 대한 가중치가 변경되면 주 버전이 증가합니다. 부 버전은 새 코드 포인트에 가중치가 할당되면 증가하지만 이전에 정렬 가능한 다른 모든 코드 포인트 가중치는 변경되지 않은 상태로 유지됩니다.

참고

주 버전의 경우 애플리케이션이 비교가 유효하도록 모든 데이터를 다시 인덱싱해야 하므로 하나 이상의 코드 포인트가 변경됩니다. 부 버전의 경우 아무것도 이동되지 않지만 코드 포인트가 추가됩니다. 이 버전의 경우 애플리케이션은 이전에 정렬할 수 없는 값으로 문자열을 다시 인덱싱해야 합니다.

 

중요

주 버전은 Windows 8 변경되었습니다. 이전 버전의 Windows에서 만든 데이터는 다시 인덱싱해야 합니다.

 

정의된 버전과 NLS 버전은 모두 LCMAP_SORTKEY 플래그가 있는 LCMapString 또는 LCMapStringEx 함수 를 사용하여 검색된 정렬 가능한 코드 포인트에 적용되며 CompareString, CompareStringEx, FindNLSStringFindNLSStringEx 함수에서도 사용됩니다. 문자열에 있는 하나 이상의 코드 요소를 정렬할 수 없는 경우 IsNLSDefinedString 함수는 해당 문자열이 매개 변수로 전달될 때 FALSE 를 반환합니다.

애플리케이션은 GetNLSVersion 또는 GetNLSVersionEx 를 호출하여 정렬 테이블에 대해 정의된 버전과 NLS 버전을 모두 검색할 수 있습니다.

데이터베이스 인덱싱

성능상의 이유로 애플리케이션은 데이터베이스를 인덱싱할 때 이 절차를 따라야 합니다.

데이터베이스를 올바르게 인덱싱하려면

  1. 각 함수에 대해 NLS 버전, 해당 버전의 정렬 키 및 인덱싱된 각 문자열에 대한 정렬 가능성을 표시합니다.
  2. 부 버전이 증가하면 이전에 정렬할 수 없는 문자열을 다시 인덱싱합니다. 이 업데이트의 영향을 받는 문자열은 IsNLSDefinedString 이 이전에 FALSE를 반환한 문자열로 제한되어야 합니다.
  3. 주 버전이 증가하면 업데이트된 가중치가 모든 문자열의 동작을 변경할 수 있으므로 모든 문자열을 다시 인덱싱합니다. 주 버전 릴리스는 매우 드물다.

데이터베이스 인덱싱 문제는 다음과 같은 이유로 발생할 수 있습니다.

  • 이후 운영 체제는 이전 운영 체제에 대해 정의되지 않은 코드 포인트를 정의하여 정렬을 변경할 수 있습니다.
  • 언어 지원의 수정으로 인해 코드 포인트는 다른 운영 체제에서 서로 다른 정렬 가중치를 가질 수 있습니다.

이러한 상황에서 데이터베이스를 다시 인덱싱할 필요성을 최소화하기 위해 애플리케이션은 IsNLSDefinedString을 사용하여 정의되지 않은 문자열과 정의되지 않은 문자열을 구분하여 애플리케이션이 정의되지 않은 코드 포인트가 있는 문자열을 거부할 수 있습니다. GetNLSVersion 또는 GetNLSVersionEx를 사용하면 애플리케이션에서 NLS 변경이 특정 인덱스 테이블에 사용되는 로캘에 영향을 미치는지 확인할 수 있습니다. 변경 내용이 로캘에 영향을 주지 않으면 애플리케이션에서 테이블을 다시 인덱싱할 필요가 없습니다.

예제

다음 표에서는 정렬 함수와 함께 사용되는 특정 플래그의 효과를 보여 줍니다. 각 경우에 플래그를 선택하면 정렬 목적으로 서로 다른 두 문자가 같은 것으로 간주되는지 여부가 결정됩니다.

문자 1 문자 2 기본값 NORM_IGNOREWIDTH NORM_IGNOREKANA NORM_IGNOREWIDTH| NORMIGNOREKANA
"あ"
U+3042 히라가나 문자 A
"ガ"
U+30A2 가타카나 문자 A
불평등 불평등 같음 같음
"オ"
U+FF75 HALFWIDTH KATAKANA LETTER O
"オ"
U+30AA 가타카나 문자 O
불평등 같음 불평등 같음
"B"
U+FF22 FULLWIDTH 라틴어 대문자 B
“B”
U+0042 라틴어 대문자 B
불평등 같음 불평등 같음

 

국가별 언어 지원 사용

정렬

로캘 정보 검색 및 설정

유니코드 정규화를 사용하여 문자열 표시

보안 고려 사항: 국가별 기능

CompareString

CompareStringEx

CompareStringOrdinal

FindNLSString

FindNLSStringEx

LCMapString

LCMapStringEx