다음을 통해 공유


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

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

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

정렬 함수

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

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

또 다른 예로는 베트남어가 있으며, 이 언어에는 "GI", "Gi", "gi"와 같은 유효한 대문자, 제목 대/소문자, 소문자 형태를 포함한 많은 두 문자 요소가 포함되어 있습니다. 이러한 형식은 하나의 단일 정렬 요소로 처리되며, 대소문자를 무시할 경우 동일하게 비교됩니다. 그러나 "gI"는 단일 요소로 유효하지 않으므로 CompareString, CompareStringEx, lstrcmplstrcmpi 는 "gI"를 두 개의 개별 요소로 처리합니다.

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

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

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

단어 정렬 문자열 정렬
직위 빌의
청구서 지위
빌의 청구서
할 수 없다 할 수 없습니다
은어 할 수 없다
할 수 없다 은어
사기 co-op
닭장 전과자
co-op 닭장

 

언어적으로 문자열 정렬

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

메모

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

 

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

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

  • 많은 로캘은 ae 합자(æ)를 ae 문자와 동일시합니다. 그러나 아이슬란드어의 문자는 별도의 문자로 간주하여 Z 뒤에 정렬 순서에 배치합니다.
  • A 문자(Å)는 일반적으로 A와 단지 음절 차이로 정렬됩니다. 그러나 스웨덴에서는 정렬할 때 A 문자가 Z 뒤에 옵니다.

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

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

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

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

예를 들어 검색된 데이터를 미리 정의된 목록이나 내부 값과 비교할 때 로캘에 관계없이 비교 결과가 일치해야 하는 경우 애플리케이션은 CompareString 또는 CompareStringExLocale 매개 변수를 LOCALE_INVARIANT 설정해야 합니다. 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 파일 이름, 환경 변수 및 뮤텍스, 명명된 파이프 또는 mailslot의 이름이 있습니다. 대/소문자를 구분하지 않는 옵션을 제외하고 이 함수는 이진이 아닌 모든 동등성을 무시합니다. 다른 정렬 함수와 달리 언어 정렬 체계에 가중치가 부여되지 않은 코드 요소를 포함하여 모든 코드 포인트가 같은지 테스트합니다.

다음 문장은 모두 이진 비교의 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로 설정하더라도, 이러한 문자열은 서로 다르게 비교됩니다.
  • 정의되었지만 언어 정렬 가중치가 없는 코드 포인트(예: ZERO WIDTH JOINER(U+200d))는 코드 포인트 가중치가 있는 것으로 처리됩니다.
  • 이후 버전의 유니코드에 정의되어 있지만 현재 언어 테이블에 가중치가 없는 코드 포인트는 코드 포인트 가중치를 갖는 것으로 처리됩니다.
  • 유니코드에서 정의되지 않은 코드 포인트는 코드 포인트 가중치를 갖는 것으로 처리됩니다.
  • 애플리케이션이 bIgnoreCase TRUE 설정하면 함수는 언어 정렬 테이블의 정보 대신 운영 체제 대문자 테이블을 사용하여 대/소문자를 매핑합니다. 따라서 매핑은 로캘과 독립적입니다.

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

코드 포인트 정렬

일부 유니코드 코드 포인트에는 가중치가 없습니다(예: 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 바이트 값의 이진 배열인 정렬 키를 생성합니다. 정렬 키는 실제 문자열이 아니며 해당 값은 원본 문자열의 정렬 동작을 나타내지만 의미 있는 표시 값은 아닙니다.

메모

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

 

정렬 키에는 홀수 바이트가 포함될 수 있습니다. LCMAP_BYTEREV 플래그는 짝수 개의 바이트 순서만 뒤집습니다. 정렬 키의 마지막 바이트(홀수 위치)는 반전되지 않습니다. 종료 0x00 바이트가 홀수 위치 바이트인 경우 정렬 키의 마지막 바이트입니다. 종료 0x00 바이트가 짝수 위치 바이트인 경우 앞에 오는 바이트와 위치를 교환합니다.

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

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

버전 정렬 사용

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

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

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

메모

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

 

중요하다

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

 

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

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

데이터베이스 인덱싱

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

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

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

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

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

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

예제

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

캐릭터 1 문자 2 기본값 NORM_IGNOREWIDTH 노름_이그노어카나 NORM_IGNOREWIDTH| NORMIGNOREKANA
"あ"
U+3042 히라가나 문자 A
"ガ"
U+30A2 가타카나 문자 A
불평등 불평등 같다 같다
"オ"
U+FF75 반폭 가타카나 문자 O
"オ"
U+30AA 가타카나 문자 "O"
불평등 같다 불평등 같다
"B"
U+FF22 전각 라틴 대문자 B
"B"
U+0042 라틴 대문자 B
불평등 같다 불평등 같다

 

국가별 언어 지원 사용

정렬

로캘 정보 검색 및 설정하기

유니코드 정규화를 사용하여 문자열을 나타내기

보안 고려 사항: 국제 기능

CompareString

CompareStringEx

compareStringOrdinal

FindNLSString

FindNLSStringEx

LCMapString

LCMapStringEx