2015-01-02 4 views
1

커다란 오픈 소스 프로젝트를 유지하고 있으므로 I/O 앞면에서 이상한 프린지 케이스를 실행하고 있습니다.어떻게 C++ STL 파일을 읽는 동안 UTF "EN DASH"가 Portably catch 및 Handle 될 수 있습니까?

내 응용 프로그램은 다음과 같이 텍스트 행을 포함하는 사용자 매개 변수 파일을 구문 분석 :

CH3 CH2 CH2 CH2  −68.189775 2 180.0    ! TraPPE 1 

... 원하는대로 포맷되어 있기 때문에 먼저 무죄 보인다에서. 그런데 마이너스가 (-)이 아닌 UTF 문자 () 인 것을 봅니다.

ifstream 개체에 STL>> 개체를 사용하고 있습니다.

음수로 변환하려고 시도 할 때 UTF 문자에서 STL이 실패 할 경우 STL은 내부 플래그를 "bad"로 설정합니다. 이는 내 논리를 트리거하여 읽기 프로세스를 중지시킵니다. 이것은 논리가 없으면 그것을 추적하는 데 더 힘든 시간을 보냈을 것입니다.

하지만 분명히 원하는 오류 처리가 아닙니다. 나는 double>>으로 읽을 때 일반 마이너스 같은 문자를 잡아두고 문자열을 바꿔야한다면 그 문자열을 바꿔서 변환을 완료해야한다.

사용자가 파일 값을 얻기 위해 프로그램 (계산기 또는 Windows의 Excel 등)에서 복사하여 붙여 넣기 할 때 상대적으로 자주 발생하는 것처럼 보입니다.

스택 오버플로에서이 문제를 발견하지 못했지만 매우 유비 쿼터스 한 것 같습니다. 이 질문에이 몇 가지 참조 발견

c++ error cannot be used as a function, some stray error [closed]

을 ...하지만 그 코드가 비슷한의 종류를 포함하는 약간 다른 문제했지만, noncompatible "마이너스 같은"EN 대시 UTF 문자 .

누구나 두 배나 부호있는 정수를 읽을 때 악성 코드를 잡을 수있는 좋은 솔루션 (소형, 휴대 성 및 재사용이 가능한 것이 좋습니까?)이 있습니까?

참고 : 특정 슈퍼 컴퓨터가 해당 라이브러리에 액세스 할 수 없습니다에 내 일부 사용자를 믿거 나 말거나 같은 부스트 ​​또는 C++ 11을 사용하지 않으
. 가능한 한 이식성을 유지하려고 노력하고 있습니다.

+2

각 줄을 한 번에 하나씩 문자열로 읽어 들이고 수정 사항을 적용한 다음 문자열을 분할합니다 ('stringstream','regex' 또는 다른 무엇이든지 사용). –

+0

물론이긴하지만 꽤 특이하지 않습니다. 이미'문자열 '로 읽은 다음 해당 문자의 코드로 바꿀 수 있다는 것을 알고 있습니다 ... http://www.fileformat.info/info/ unicode/char/2013/index.htm ... ifstream을 래핑하여 해당 사례를 잡을 수 있습니까? 아무튼 나는 누군가가 이것을 처리 할 실제 코드를 갖고 있는지보고 싶다 ... 당신의 대답은 감사하지만, 기본적으로 내가있는 곳이다. 일부는 이미이 문제를 해결하고 모범 사례/휴대용/소형 솔루션을 갖기를 바랍니다. –

+0

질문에 붙여 넣은 캐릭터는 u + 2013이 아니며 u + 2212입니다. 여러 가능성을 코드 작성해야 할 수도 있습니다. –

답변

1

사용자 정의 std::num_get을 사용할 수 있습니다. 가치 측면에 대한 다른 문자도 덮어 쓸 수 있습니다.

#include <iostream> 
#include <string> 
#include <sstream> 

class num_get : public std::num_get<wchar_t> 
{ 
public: 
    iter_type do_get(iter_type begin, iter_type end, std::ios_base & str, 
         std::ios_base::iostate & error, float & value) const 
    { 
     bool neg=false; 
     if(*begin==8722) { 
      begin++; 
      neg=true; 
     } 

     iter_type i = std::num_get<wchar_t>::do_get(begin, end, str, error, value); 

     if (!(error & std::ios_base::failbit)) 
     { 
      if(neg) 
       value=-value; 
     }  
     return i; 
    } 
}; 

int main(int argc,char ** argv) { 

    std::locale new_locale(std::cin.getloc(), new num_get); 

    // Parsing wchar_t streams makes live easier but in principle 
    // it should work with char (e.g. UTF8 as well) 

    static const std::wstring ws(L"CH3 CH2 CH2 CH2  −68.189775 2 180.0    ! TraPPE 1"); 
    std::basic_stringstream<wchar_t> wss(ws);                 
    std::wstring a; 
    std::wstring b; 
    std::wstring c; 
    float f=0; 

    // Imbue this new locale into wss 
    wss.imbue(new_locale);     

    for(int i=0;i<4;i++) { 
     std::wstring s; 
     wss >> s >> std::ws; 
     std::wcerr << s << std::endl; 
    } 

    wss >> f; 

    std::wcerr << f << std::endl; 
} 
1

수동 이외의 것은 발생하지 않습니다. 유니 코드에는 많은 수의 문자가 있습니다. 여기에는 Em 대시와 En 대시가 있으며, 대개는 그 이상입니다. 예를 들어 엠 대시 (Em Dash)의 가능성을 고려한 다음 비공개 영역을 고려한 다음 일부 숫자를 고려 했습니까? 또는 RTL 재정의? 유니 코드는 가능성이 거의 끝나지 않았고 C++에서 이중 전설이기 때문에 전설입니다. 표준 지원은 ISIS의 온전함에 대한 지원이라고 자비로 설명 될 수 있기 때문입니다.

이렇게하는 유일한 방법은 사용자가보고 할 때 각 상황을 찾고 수동으로 처리하는 것입니다. 즉, 이중으로 operator>>을 사용하지 마십시오.