2010-02-25 2 views
54

스위치의 개체가 문자열 인 switch-case 문을 사용하면 ignoreCase를 비교할 수 있습니까?C# Switch 문에서 IgnoreCase를 사용하는 방법

나는 예를 들어 있습니다

string s = "house"; 
switch (s) 
{ 
    case "houSe": s = "window"; 
} 

윌의 GET 값 "창을". ignoreCase를 사용하여 문자열을 비교할 수 있도록 switch-case 문을 재정의하는 방법은 무엇입니까?

답변

49

, 두 개의 문자열을 lowercasing하고 비교는 무시의 경우를 비교하고 동일하지 않습니다. 이것에 대한 많은 이유가 있습니다. 예를 들어, 유니 코드 표준은 발음 구별이있는 텍스트를 여러 가지 방법으로 인코딩 할 수 있습니다. 일부 문자는 기본 문자와 분음 부호를 단일 코드 포인트에 포함합니다. 이 문자들은 기본 문자와 결합 발음 구별 문자로 표시 될 수 있습니다. 이 두 표현은 모든 목적에 동일하며 .NET Framework의 문화권 인식 문자열 비교는 CurrentCulture 또는 InvariantCulture (IgnoreCase 포함 또는 제외)를 사용하여 동일하게 식별합니다. 다른 한편으로 서수 비교는 그것들을 불평등 한 것으로 잘못 간주 할 것이다.

불행히도 switch은 서수 비교를하지 않습니다. 정렬 된 코드는 엄격하게 정의 된 코드로 ASCII 파일을 구문 분석하는 것과 같은 특정 종류의 응용 프로그램에서는 좋지만 대부분의 다른 용도에서는 서수 문자열 비교가 잘못되었습니다.

올바른 행동을 취하기 위해 내가 한 일은 저의 switch 문을 조롱하는 것입니다. 이를 수행 할 수있는 방법이 많이 있습니다. 한 가지 방법은 List<T> 쌍의 사례 문자열과 대리자를 만드는 것입니다. 목록은 적절한 문자열 비교를 사용하여 검색 할 수 있습니다. 일치가 발견되면 연관된 델리게이트가 호출 될 수 있습니다.

또 다른 옵션은 if 문장의 명백한 체인을 수행하는 것입니다. 이것은 구조가 매우 규칙적이기 때문에 일반적으로 들리는 것처럼 나쁘지는 않습니다.

대단한 점은 문자열과 비교할 때 자신의 스위치 기능을 조롱하는 데 성능상의 불이익이 없다는 것입니다. 시스템은 정수로 할 수있는 방식으로 O (1) 점프 테이블을 만들지 않으므로 어쨌든 한 번에 하나씩 각 문자열을 비교하게 될 것입니다.

비교할 사례가 많고 성능이 문제가되는 경우 위에서 설명한 List<T> 옵션을 정렬 된 사전 또는 해시 테이블로 바꿀 수 있습니다. 그러면 성능이 switch 문의 옵션과 잠재적으로 일치하거나 초과 할 수 있습니다.

물론
delegate void CustomSwitchDestination(); 
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList; 
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound); 
void CustomSwitch(string value) 
{ 
    foreach (var switchOption in customSwitchList) 
     if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase)) 
     { 
      switchOption.Value.Invoke(); 
      return; 
     } 
    defaultSwitchDestination.Invoke(); 
} 

, 당신은 아마도 아마도 몇 가지 표준 매개 변수와 CustomSwitchDestination 위임에 반환 유형을 추가 할 것 : 여기

는 대표 목록의 예입니다. 그리고 당신은 더 나은 이름을 만들고 싶어합니다!

differnt 매개 변수가 필요한 경우와 같이 각 사례의 동작이 이러한 방식으로 호출을 위임 할 수없는 경우 연결된 if 문장이 붙어 있습니다. 나는 이것을 몇 번 했어.

if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase)) 
    { 
     s = "window"; 
    } 
    else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase)) 
    { 
     s = "really big window"; 
    } 
    else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase)) 
    { 
     s = "broken window"; 
    } 
+4

내가 틀린 것이 아니라면이 두 언어는 특정 문화권 (터키어 등)에서만 다르며이 경우 'ToUpperInvariant()'또는 'ToLowerInvariant()'를 사용할 수 없습니까? 또한, 그는 두 개의 알려지지 않은 문자열을 비교하지 않습니다. 그는 하나의 알려지지 않은 문자열과 알려진 문자열을 비교합니다. 따라서 적절한 대소 문자 표현을 하드 코딩하는 방법을 알고있는 한 스위치 블록이 잘 작동해야합니다. –

+5

@Seth Petry-Johnson - 최적화가 가능할 수도 있지만 문자열 비교 옵션이 프레임 워크에 구워지는 이유는 올바른 확장 가능한 소프트웨어를 작성하는 데 언어학 전문가가되어야하는 것은 아닙니다. –

+34

확인. 이것이 relivant 인 경우를 예로 들어 보겠습니다. "집"대신에 우리는 (영어!) 단어 "카페"를 가지고 있다고 가정합니다. 이 값은 "caf \ u00E9"또는 "cafe \ u0301"에 의해 동일하게 잘 표현 될 수 있습니다. 'ToLower()'또는 'ToLowerInvariant()'와 같은 서수 항등식 (switch 문에서와 같이)은 false를 반환합니다. 'Equals'와'StringComparison.InvariantCultureIgnoreCase'는 true를 리턴합니다. 두 시퀀스는 표시 될 때 동일하게 보이기 때문에'ToLower()'버전은 추적하기에 더러운 버그입니다. 터키인이 아니더라도 적절한 문자열 비교를하는 것이 항상 최선의 방법입니다. –

59

더 간단한 접근법은 switch 문에 들어가기 전에 문자열을 소문자로 구분하는 것입니다.

실제로 상위는 순수한 극단적 인 나노초 성능의 관점에서 조금 나아졌지만 보는 것은 덜 자연 스럽습니다.

예컨대 : 당신이 알고 있어야하는 것으로

string s = "house"; 
switch (s.ToLower()) { 
    case "house": 
    s = "window"; 
    break; 
} 
+0

@ 닉, 하위 전환과 상위 전환의 실적 차이에 대한 이유는 무엇입니까? 호기심에 도전하지 마라. – Lazarus

+1

그래, 나는 lowercasing은 방법이지만, 나는 그것을 ignoreCase하고 싶습니다. switch-case 문을 무시할 수있는 방법이 있습니까? – Tolsan

+6

@Lazarus - 이것은 CLR에서 C#을 통해 얻은 것입니다. 숨겨진 기능 스레드에서 다시 게시되었습니다. http://stackoverflow.com/questions/9033/hidden-features-of-c/12137#12137 You 수백만 번의 반복으로 LinqPad를 가동시킬 수 있습니다. –

20

경우에 따라 열거 형을 사용하는 것이 좋습니다. 따라서 먼저 enum을 구문 분석하고 (ignoreCase 플래그 true로) 열거 형을 전환하십시오.

SampleEnum Result; 
bool Success = SampleEnum.TryParse(inputText, true, out Result); 
if(!Success){ 
    //value was not in the enum values 
}else{ 
    switch (Result) { 
     case SampleEnum.Value1: 
     break; 
     case SampleEnum.Value2: 
     break; 
     default: 
     //do default behaviour 
     break; 
    } 
} 
+0

참고 사항 : Enum TryParse는 Framework 4.0 및 이후 버전에서 사용할 수있는 것으로 보입니다 (참고로 FYI). http://msdn.microsoft.com/en-us/library/dd991317(v=vs.100).aspx – granadaCoder

+0

마법의 문자열을 사용하지 않기 때문에이 솔루션을 선호합니다. – user1069816

11

한 가지 가능한 방법은 작업 위임과 함께 무시 사전을 사용하는 것입니다.

string s = null; 
var dic = new Dictionary<string, Action>(StringComparer.CurrentCultureIgnoreCase) 
{ 
    {"house", () => s = "window"}, 
    {"house2",() => s = "window2"} 
}; 

dic["HouSe"](); 
+0

이 솔루션은 더 높아야합니다 ... – vipero07

+1

'CurrentCultureIgnoreCase'가 아니라 ['OrdinalIgnoreCase'] (https://msdn.microsoft.com/en-us/library/ms973919.aspx)가 좋습니다. –

1

나는이 특별한 경우에 소문자 나 대문자 중 하나를 전체 문자열로 변환하고 비교를 위해 소문자 문자열을 사용하려고 도움이되기를 바랍니다 : 오래된 질문에 새로운 게시물에 대한

public string ConvertMeasurements(string unitType, string value) 
{ 
    switch (unitType.ToLower()) 
    { 
     case "mmol/l": return (Double.Parse(value) * 0.0555).ToString(); 
     case "mg/dl": return (double.Parse(value) * 18.0182).ToString(); 
    } 
} 
6

죄송합니다 그러나 C# 7 (VS 2017)을 사용하여이 문제를 해결하는 새로운 옵션이 있습니다.

C는 # 7 현재 "패턴 일치"를 제공, 그리고 thusly 히이 문제를 해결하는 데 사용할 수 있습니다

string houseName = "house"; // value to be tested, ignoring case 
string windowName; // switch block will set value here 

switch (true) 
{ 
    case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase): 
     windowName = "MyWindow"; 
     break; 
    case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase): 
     windowName = "YourWindow"; 
     break; 
    case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase): 
     windowName = "Window"; 
     break; 
    default: 
     windowName = null; 
} 

이 솔루션은 또한 @Jeffrey L Whitledge에 의해이 질문에 언급되는 문제를 다루는 대소 문자를 문자열의 비 구분 비교는 두 개의 하위 사례 문자열 비교와 동일하지 않습니다.

그런데 2017 년 2 월에 Visual Studio Magazine에서 패턴 일치를 설명하고이 패턴을 사례 블록에서 사용하는 방법에 대한 흥미로운 기사가있었습니다. 제발 봐 : Pattern Matching in C# 7.0 Case Blocks

+0

더 길어 지겠지 만'switch (houseName)'을 사용하는 것과 비슷한 비교를 할 것입니다. 즉, 'case var name when name.Equals ("MyHouse", ...' – LewisM

+0

@LewisM - 흥미 롭습니다. 실용적인 예를 보여줄 수 있습니까? – STLDeveloper

0

@ STLDeveloperA에 의해 답변에 대한 확장. C# 7 현재 문 switch 문 패턴 매칭을 사용하는 경우, 새로운 방법은 여러없이 문 평가를 위해,이 방법은 가변 존재에 전환하고 있지만 방식 @STLDeveloper 마찬가지로

string houseName = "house"; // value to be tested 
string s; 
switch (houseName) 
{ 
    case var name when name.Equals("Bungalow", StringComparison.InvariantCultureIgnoreCase): 
     s = "Single glazed"; 
    break; 

    case var name when name.Equals("Church", StringComparison.InvariantCultureIgnoreCase); 
     s = "Stained glass"; 
     break; 
     ... 
    default: 
     s = "No windows (cold or dark)" 
     break; 
} 

비주얼 스튜디오 잡지 투입 가치가있는 nice article on pattern matching case blocks이 있습니다.