2014-08-29 5 views
5

이전의 질문 : Why `strchr` seems to work with multibyte characters, despite man page disclaimer?에 뒤이어, strchr는 나쁜 선택이었습니다. `strstr`을 사용하여 문자열의 멀티 바이트 UTF-8 문자를 검색하는 것이 안전합니까?

대신 내가 단일 문자를 찾기 위해 strstr를 사용하는 방법에 대해 생각하고 (멀티 바이트하지 char) :

const char str[] = "This string contains é which is a multi-byte character"; 
char * pos = strstr(str, "é"); // 'é' = 0xC3A9: 2 bytes 
printf("%s\n", pos); 

OUPUT :

é 멀티 바이트를 문자

입니다

내 멀티 바이트 문자의 첫 번째 바이트의 위치는 다음과 같습니다.

선험적으로, 이것은 strstr의 표준적인 사용은 아니지만 잘 작동하는 것 같습니다.
이 해결 방법은 안전한가요? 버그를 유발할 수있는 부작용이나 특별한 경우에 대해 생각해 볼 수 있습니까?

[편집] : 내가해야 정확한 나는 wchar_t 유형과 내가 처리 할 문자열이 UTF-8로 인코딩 된 것을 (나는이 choice 논의 할 수 있습니다 알고 있지만 관련없는 논쟁)

+0

_ "선험적으로, 이것은 표준이 아닙니다."_ 그렇습니까? UTF8로 인코딩 된 문자열 일뿐입니다. –

+0

@AdrianoRepetti UTF8 일 필요는 없습니다. –

+0

그것은 당신의 구현이 얼마나 "정상적인 "지에 달려 있습니다. 로케일 특정 멀티 바이트 인코딩은 UTF-7 (또는 상태를 갖는 다른 것)이 될 수 있습니다.이 경우'strstr'은 거짓 긍정을 산출 할 수 있습니다. – mafso

답변

4

없음 strstr 멀티 바이트 문자를 포함하는 문자열에 적합하지 않습니다.

멀티 바이트 문자가 포함 된 문자열 내에 멀티 바이트 문자가 포함되지 않은 문자열을 검색하는 경우 거짓 긍정을 줄 수 있습니다. (C1)의 일부를 후행하는 (실수) C5와 일치하는 경우에 당신은 잘못된 결과를 얻을 수

+---------+----+----+----+ 
| c1 | c2 | c3 | c4 | <--- string 
+---------+----+----+----+ 

    +----+----+----+ 
    | c5 | c2 | c3 | <--- string to search 
    +----+----+----+ 

을 (일본어 로케일 않는 strstr ("掘 무엇인가"에 shift-jis encoding을 사용하는 동안, "@some")는 오 탐지를 제공 할 수 있습니다). 유니 코드 부분 문자열 검사 기능 또는 멀티 바이트 부분 문자열 검사 기능을 사용하여 유니 코드를 사용하는 것이 좋습니다. (예를 들어 _mbsstr)

편집
그래서 대답은 UTF-8이 그러한 방식으로 설계된다 "긍정적 인 거짓이 UTF-8 환경에서 이러한 존재할 수있다"고 OP에서 업데이트 된 질문을 바탕으로 위에 표시된 것처럼 문자의 부분 불일치에 면역되며 잘못된 양성을 유발합니다. 따라서 strstr을 UTF-8로 코딩 된 멀티 바이트 문자와 함께 사용하는 것이 안전합니다.

+0

고마워, 나는 뭔가를 놓친 직감을 가졌다. 그러나 지금 질문은 : UTF-8 환경에서 위양성이 존재할 수 있는가하는 것입니다. – Coconop

+4

문자의 첫 번째 바이트는 가능한 후속 문자와 항상 다르기 때문에 UTF-8에서 오 탐지 (false positive)를 얻을 수 없습니다. –

+3

로스는 이미 UTF-8에 strstr을 사용하고 완전히 안전하다고 언급했기 때문에. UTF-8 코드는 UTF-8 문자 집합의 문자간에 오 탐지가 불가능한 방식으로 생성됩니다. –

-2
를 사용하지 않는 것이

이 해결 방법은 안전한가요? 버그를 유발할 수있는 부작용이나 특별한 경우에 대해 생각해 볼 수 있습니까?

부작용은 strtr()이 일치하는 항목을 찾지 못하면 Segmentation fault이되는 널 포인터 값을 인쇄한다는 것입니다.

문자열을 인쇄하기 전에 포인터에 NULL 값이 있는지 확인해야합니다. 이런 식으로 확인 :

if(pos == NULL) 
    printf("letter not found"); 
else 
    printf("%s\n", pos); 
+1

주 질문에 대답하지 않기 때문에 주석으로 더 적합합니다. –

+0

나는 주된 질문에 대답했다. 문자열의 멀티 바이트 및 "일반"문자에는 차이가 없습니다. – Igor

+3

주된 질문은 'strstr'이 멀티 바이트 문자열에 대해 작동하는지 아닌지, "내 코드에는 어떤 문제가 있습니까?" –

1

최신 시스템은이 기능의 사용이 안전한 다중 바이트 인코딩으로 UTF-8 (또는 ASCII)을 사용합니다.

이전/이국적인 플랫폼에서도 코드를 엄격하게 준수하고 추가 작업을 수행하려면 추가 문제를 고려해야합니다.

첫째, 좋은 소식 : 모든 멀티 바이트 인코딩에서 0 바이트는 상태에 관계없이 문자열의 끝을 나타냅니다. 즉, strstr에서 충돌이나 문제가 발생하지 않지만 결과가 잘못되었을 수 있습니다.

예를 들어, 유니 코드를 인코딩하는 7 비트의 깔끔한 방법 인 UTF-7을 고려해보십시오. UTF-7은 시프트 상태 인을 갖는 멀티 바이트 인코딩입니다. 이는 바이트가 해석되는 방식이 나타나는 컨텍스트에 따라 다를 수 있음을 의미합니다. 예 : (Wikipedia 참조) "£ 1AKM"은 기호가 상태를 변경하고 A과 같은 문자의 해석을 나타내는 UTF-7에서 +AKM-AKM으로 인코딩됩니다. strstr(str, "AKM")을 수행하면 첫 번째 AKM 부분 (+ 다음)이 인코딩의 일부이고 £인데 실제로는 - 다음에 AKM 부분과 일치해야합니다 (시프트 상태를 다시 초기 상태로 설정).

+0

내가 UTF-8 인코딩을 사용한다는 사실을 잊어 버렸지 만 어쨌든 팁을 주셔서 감사합니다. – Coconop