대문자 대 소문자


85

대소 문자를 구분하지 않는 비교를 할 때 문자열을 대문자 또는 소문자로 변환하는 것이 더 효율적입니까? 그것이 중요합니까?

이 SO 게시물 에서는 "Microsoft가 그렇게 최적화했기 때문에 C #이 ToUpper와 함께 더 효율적 이라고 제안 합니다." 그러나 ToLower 대 ToUpper를 변환하는 것은 문자열에 더 많은 내용이 포함되어 있고 일반적으로 문자열에 더 많은 소문자가 포함되어 ToLower를 더 효율적으로 만든다는 이 주장 을 읽었습니다 .

특히 다음 사항을 알고 싶습니다.

  • 하나가 다른 것보다 빠르도록 ToUpper 또는 ToLower를 최적화하는 방법이 있습니까?
  • 대문자 또는 소문자 문자열을 대소 문자를 구분하지 않고 비교하는 것이 더 빠르며 그 이유는 무엇입니까?
  • 한 경우가 다른 경우보다 분명히 나은 프로그래밍 환경 (예 : C, C #, Python 등)이 있습니까? 그 이유는 무엇입니까?

답변:


90

대소 문자를 구분하지 않고 비교하기 위해 대문자 또는 소문자로 변환하는 것은 일부 문화권, 특히 터키의 "흥미로운"기능으로 인해 올바르지 않습니다. 대신 적절한 옵션과 함께 StringComparer를 사용하십시오.

MSDN에는 문자열 처리에 대한 몇 가지 훌륭한 지침이 있습니다. 또한 코드가 Turkey 테스트를 통과하는지 확인할 수도 있습니다 .

편집 : 서수 대소 문자를 구분하지 않는 비교에 대한 Neil의 설명을 참고하십시오 . 이 전체 영역은 꽤 어둡습니다 :(


15
예 StringComparer는 훌륭하지만 질문에 대한 답변이 없습니다. 문자열에 대한 swtich 문과 같은 StringComparer를 사용할 수없는 상황에서; 스위치에서 ToUpper 또는 ToLower를해야합니까?
joshperry

7
ToUpper 또는 ToLower를 사용하는 대신 StringComparer 및 "if"/ "else"를 사용하십시오.
Jon Skeet

5
John, 소문자로 변환하는 것이 올바르지 않다는 것을 알고 있지만 대문자로 변환하는 것이 올바르지 않다는 말은 들어 본 적이 없습니다. 예나 참조를 제공 할 수 있습니까? 링크 된 MSDN 기사는 다음과 같이 말합니다. "OrdinalIgnoreCase를 사용하여 만든 비교는 동작 적으로 두 호출의 구성입니다. 두 문자열 인수에서 ToUpperInvariant를 호출하고 서수 비교를 수행합니다." "서수 문자열 연산"섹션에서는이를 코드로 다시 설명합니다.
Neil

2
@ 닐 : 흥미 롭 네요, 저는 그 비트를 보지 못했습니다. 를 들어 순서 대소 문자를 구분 비교, 그게 공평 같아요. 결국 뭔가 를 선택 해야합니다. 문화적으로 구분되는 대소 문자를 구분하지 않는 비교의 경우 여전히 이상한 행동의 여지가 있다고 생각합니다. 이 질문에 대해 귀하의 코멘트 ... 지적 할 것이다
존 소총

4
@ Triynko : 오답을 빨리 얻는 것이 일반적으로 오답을 천천히 얻는 것보다 낫지 않다 (때로는 더 나쁘다)는 점에서 주로 정확성 에 집중 하는 것이 중요하다고 생각합니다 .
Jon Skeet 2011 년

25

에서 마이크로 소프트 MSDN에 :

.NET Framework에서 문자열을 사용하기위한 모범 사례

문자열 사용에 대한 권장 사항

왜? 에서 마이크로 소프트 :

문자열을 대문자로 정규화

소문자로 변환 할 때 왕복 할 수없는 작은 문자 그룹이 있습니다.

왕복 할 수없는 캐릭터의 예는 무엇입니까?

  • 시작 : 그리스로 기호 (U + 03f1) ϱ
  • 대문자 : Capital Greek Rho (U + 03a1) Ρ
  • 소문자 : 작은 그리스어 Rho (U + 03c1) ρ

ϱ, Ρ , ρ

.NET 바이올린

Original: ϱ
ToUpper: Ρ
ToLower: ρ

그렇기 때문에 대소 문자를 구분하지 않는 비교를하려면 문자열을 소문자가 아닌 대문자로 변환해야합니다.

따라서 하나를 선택해야하는 경우 대문자를 선택하십시오 .


그 이유는 무엇입니까?
bjan

@bjan 그 이유는 나쁘지 않기 때문입니다.
Ian Boyd

1
어떤 캐릭터 그룹? 은 무슨 뜻인가요?
johv

1
@johv 링크에서 : "왕복을 만든다는 것은 한 로케일에서 문자 데이터를 다르게 나타내는 다른 로케일로 문자를 변환 한 다음 변환 된 문자에서 원래 문자를 정확하게 검색하는 것을 의미합니다." 어떤 캐릭터 그룹? 나도 몰라,하지만 난 소문자 추측거야 i될 때 터키어,에서를 İ오히려보다, I당신이 사용하고있다. 또한 우리는 대문자 I가 되는데 익숙 i하지만 터키에서는 ı.
Ian Boyd

3
원래 질문에 대한 답변으로 돌아 가기 : 하나의 대문자 변형에 대해 둘 이상의 소문자 변형을 아는 언어가 있습니다. 언제 어떤 표현을 사용할 지에 대한 규칙을 모르는 경우 (그리스어로 된 또 다른 예 : 작은 시그마 문자, 단어 시작 또는 중간에 σ를 사용하고 단어 끝에 ς를 사용합니다 ( en.wikipedia.org/wiki/Sigma 참조 ). 소문자 변형으로 안전하게 다시 변환 할 수 없습니다
Aconcagua

19

MSDN 에 따르면 문자열을 전달하고 대소 문자를 무시하도록 비교하는 것이 더 효율적입니다.

String.Compare (strA, strB, StringComparison.OrdinalIgnoreCase)는 호출 과 동일 하지만 (보다 빠릅니다 )

String.Compare (ToUpperInvariant (strA), ToUpperInvariant (strB), StringComparison.Ordinal).

이러한 비교는 여전히 매우 빠릅니다.

물론, 하나의 문자열을 계속해서 비교한다면 이것은 유지되지 않을 수 있습니다.


12

더 많은 소문자 항목을 갖는 경향이있는 문자열을 기반으로, ToLower는 이론적으로 더 빠릅니다 (많은 비교이지만 할당은 거의 없음).

C에서 또는 각 문자열의 개별적으로 액세스 할 수있는 요소 (예 : C 문자열 또는 C ++의 STL 문자열 유형)를 사용하는 경우 실제로는 바이트 비교이므로 비교 UPPERlower.

교활하고 문자열을 long대신 배열에 로드 하면 한 번에 4 바이트를 비교할 수 있기 때문에 전체 문자열에 대해 매우 빠른 비교를 얻을 수 있습니다. 그러나로드 시간으로 인해 가치가 없을 수 있습니다.

어떤 것이 더 빠른지 알아야하는 이유는 무엇입니까? 비교의 통계적 버트로드를 수행하지 않는 한, 몇 사이클 더 빠르게 실행하는 것은 전체 실행 속도와 관련이 없으며 조기 최적화처럼 들립니다. :)


11
어떤 것이 더 빠른지 알아야하는 이유에 대한 질문에 답하기 위해, 나는 알 필요가없고 단지 알고 싶습니다. :) 단순히 누군가가 주장하는 것을보고 (예 : "대문자 문자열을 비교하는 것이 더 빠릅니다!") 그것이 진실인지 그리고 / 또는 그들이 주장한 이유를 알고 싶어하는 경우입니다.
Parappa

1
그게 말이 돼요-저도 이런 것들에 대해 영원히 궁금 해요 :)
warren

C 문자열 을 사용하여 문자열이 같더라도 문자열이 같도록 long 배열 로 변환 s하고 t종료 '\0'문자 를 찾을 때까지 s와 t를 걸어야합니다 (또는 문자열 끝을지나 가비지를 비교할 수 있습니다. 정의되지 않은 동작을 호출하는 잘못된 메모리 액세스 일 수 있습니다.) 그런데 캐릭터를 하나씩 훑어 보면서 비교 만 해보는 건 어떨까요? C ++ 문자열을 사용하면 길이 and를 가져 와서 .c_str()캐스트 하고 length long *의 접두사를 비교할 수 .size() - .size()%(sizeof long)있습니다. 나에게 약간 수상한 것 같습니다.
Jonas Kölker

6

마이크로 소프트는 최적화있다 ToUpperInvariant(), 없다 ToUpper(). 차이점은 불변성이 더 문화 친화적이라는 것입니다. 문화권이 다를 수있는 문자열에 대해 대 / 소문자를 구분하지 않는 비교를 수행해야하는 경우 Invariant를 사용하십시오. 그렇지 않으면 고정 변환의 성능이 중요하지 않습니다.

ToUpper () 또는 ToLower ()가 더 빠르다고 말할 수 없습니다. 성능이 그다지 중요한 상황이 없었기 때문에 한 번도 시도한 적이 없습니다.


Microsoft가 대문자 비교를 수행하기 위해 코드를 최적화했다면 대문자에 대한 ASCII 코드는 65-90이고 ASCII 코드는 3 자리를 포함하는 소문자 97-122 (더 많은 처리가 필요함) 때문입니까?
메디아 메디아

3
@Medo 나는 최적화의 정확한 이유를 기억하지 못하지만 모든 문자가 이진수로 저장되기 때문에 2 대 3 자리는 거의 확실한 이유가 아니므로 십진수는 실제로 저장 방식에 따라 의미가 없습니다.
Dan Herbert

4

C #에서 문자열 비교를 수행하는 경우 두 문자열을 모두 대문자 또는 소문자로 변환하는 대신 .Equals ()를 사용하는 것이 훨씬 빠릅니다. .Equals () 사용에 대한 또 다른 큰 장점은 2 개의 새로운 대문자 / 소문자 문자열에 더 많은 메모리가 할당되지 않는다는 것입니다.


4
그리고 보너스로 올바른 옵션을 선택하면 실제로 올바른 결과를 얻을 수 있습니다. :)
Jon Skeet

1

정말 중요하지 않습니다. ASCII 문자를 사용하면 확실히 문제가되지 않습니다. 단지 몇 번의 비교와 어느 방향 으로든 약간 뒤집기 만하면됩니다. 유니 코드는 이상한 방식으로 대소 문자를 바꾸는 문자가 있기 때문에 조금 더 복잡 할 수 있지만 텍스트가 특수 문자로 가득 차 있지 않으면 실제로 차이가 없어야합니다.


1

올바르게 수행하면 소문자로 변환하는 경우 속도 이점이 작지만 중요하지 않을 것입니다. 메모리에 대한 할당이 거의 없음을 의미합니다.)-대문자가 많은 문자열이있는 경우 대문자로 변환하는 것이 더 빠릅니다.


0

때에 따라 다르지. 위에서 언급했듯이 일반 ASCII 만 동일합니다. .NET에서 String.Compare 에 대해 읽고 i18n 항목 (언어 문화 및 유니 코드)에 대한 올바른 비교를 사용합니다. 입력 가능성에 대해 알고있는 경우 더 일반적인 경우를 사용하십시오.

다중 문자열 비교를 수행하는 경우 길이가 훌륭한 첫 번째 판별 자임을 기억하십시오.


-2

순수 ASCII로 처리하는 경우에는 중요하지 않습니다. 그것은 단지 OR x, 32 대 AND x, 224입니다. 유니 코드, 모르겠어요 ...


4
이것은 완전히 잘못된 것입니다. 32로 OR는 AZ와 64-127 문자에서만 작동합니다. 다른 모든 캐릭터를 망쳐 놓습니다. AND'ing 32는 훨씬 더 잘못되었습니다. 결과는 항상 0 (nul) 또는 32 (공백)입니다.
Adam Rosenfield
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.