fopen для всего - это возможно? - PullRequest
24 голосов
/ 25 июля 2011

Я привык к программированию окон, но хочу попробовать свои силы в создании кроссплатформенного приложения. И у меня есть несколько вопросов, если вы не возражаете:

Вопрос 1

Есть ли какой-нибудь способ открыть файл UNICODE \ ASCII и автоматически определить его кодировку с использованием чистого ANSI C. MSDN говорит, что fopen () может переключаться между различными форматами UNICODE (utf-8, utf-16, UNICODE BI \ LI), если Я буду использовать флаг "ccs = UNICODE". Экспериментально установлено, что переключения с UNICODE на ASCII не происходит, но, пытаясь решить эту проблему, я обнаружил, что текстовые файлы Unicode имеют некоторые префиксы, такие как 0xFFFE, 0xFEFF или 0xFEBB.

FILE *file;
{
 __int16 isUni;
 file = _tfopen(filename, _T("rb"));
 fread(&(isUni),1,2,file);
 fclose(file);
 if( isUni == (__int16)0xFFFE || isUni == (__int16)0xFEFF || isUni == (__int16)0xFEBB)
  file = _tfopen(filename, _T("r,ccs=UNICODE"));
 else
  file = _tfopen(filename, _T("r"));         
}

Так, я могу сделать что-то вроде этого кроссплатформенного и не настолько уродливого?

Вопрос 2

Я могу сделать что-то подобное в Windows, но будет ли это работать в Linux?

file = fopen(filename, "r");
fwscanf(file,"%lf",buffer);

Если нет, то существует ли какая-либо функция ANSI C для преобразования строк ASCII в Unicode? Я хочу работать со строками Unicode в моей программе.

Вопрос 3

Кроме того, мне нужно вывести строки Unicode в консоль. В Windows есть setlocale (*), но что мне делать в Linux? Похоже, консоль уже есть в Unicode.

Вопрос 4

Вообще говоря, я хочу работать с Unicode в моей программе, но я столкнулся с некоторыми странными проблемами:

f = fopen("inc.txt","rt");
fwprintf(f,L"Текст");            // converted successfully
fclose(f);
f = fopen("inc_u8.txt","rt, ccs = UNICODE");
fprintf(f,"text");               // failed to convert
fclose(f);

P.S. Есть ли какая-нибудь хорошая книга о кроссплатформенном программировании, чем-то со сравнением кода для Windows и Linux-программ? И какая-то книга о способах использования Unicode, практических методах, то есть. Я не хочу погружаться в простую историю UNICODE BI \ LI, меня интересуют конкретные библиотеки C / C ++.

Ответы [ 2 ]

2 голосов
/ 27 июля 2011

Вопрос 1:

Да, вы можете определить метку порядка байтов, которая является последовательностью байтов, которую вы обнаружили - ЕСЛИ ВАШ ФАЙЛ ЕСТЬ ОДИН.Поиск в Google и stackoverflow сделают все остальное.Что касается «не так некрасиво»: вы можете реорганизовать / украсить свой код, например, написать функцию для определения спецификации и сделать это в начале, а затем вызвать fopen или _tfopen, как требуется.Затем вы можете снова выполнить рефакторинг и написать свою собственную функцию fopen.Но это все равно будет ужасно.

Вопрос 2:

Да, но функции Unicode не всегда вызываются одинаково в Linux, как и в Windows.Использование определяет.Возможно напишите свой собственный TCHAR.H

Вопрос 3:

#include <locale.h>
setlocale(LC_ALL, "en.UTF-8")

man 3 setlocale

Вопрос 4:Просто используйте fwprintf.Другое не является стандартным.

Вы можете использовать инструментарий wxWidgets.Он использует Unicode, и он использует классы, которые имеют реализации для одной и той же вещи в Windows, Linux и Unix и Mac.

Лучший вопрос для вас - как конвертировать ASCII в Unicode и наоборот.Это выглядит следующим образом:

std::string Unicode2ASCII( std::wstring wstrStringToConvert )
{
    size_t sze_StringLength = wstrStringToConvert.length()  ;

    if(0 == sze_StringLength)
        return "" ;

    char* chrarry_Buffer = new char[ sze_StringLength + 1 ] ;
    wcstombs( chrarry_Buffer, wstrStringToConvert.c_str(), sze_StringLength ) ; // Unicode2ASCII, const wchar_t* C-String 2 mulibyte C-String
    chrarry_Buffer[sze_StringLength] = '\0'     ;
    std::string strASCIIstring = chrarry_Buffer ;
    delete chrarry_Buffer ;

    return strASCIIstring ;
}


std::wstring ASCII2Unicode( std::string strStringToConvert )
{
    size_t sze_StringLength = strStringToConvert.length() ;

    if(0 == sze_StringLength)
        return L"" ;

    wchar_t* wchrarry_Buffer = new wchar_t[ sze_StringLength + 1 ] ;
    mbstowcs( wchrarry_Buffer, strStringToConvert.c_str(), sze_StringLength ) ; // Unicode2ASCII, const. mulibyte C-String 2 wchar_t* C-String
    wchrarry_Buffer[sze_StringLength] = L'\0'    ;
    std::wstring wstrUnicodeString = wchrarry_Buffer ;
    delete wchrarry_Buffer   ;

    return wstrUnicodeString ;
}

Редактировать: Вот некоторые сведения о доступных функциях Unicode в Linux (wchar.h):

__BEGIN_NAMESPACE_STD
/* Copy SRC to DEST.  */
extern wchar_t *wcscpy (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;
/* Copy no more than N wide-characters of SRC to DEST.  */
extern wchar_t *wcsncpy (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;

/* Append SRC onto DEST.  */
extern wchar_t *wcscat (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;
/* Append no more than N wide-characters of SRC onto DEST.  */
extern wchar_t *wcsncat (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;

/* Compare S1 and S2.  */
extern int wcscmp (__const wchar_t *__s1, __const wchar_t *__s2)
     __THROW __attribute_pure__;
/* Compare N wide-characters of S1 and S2.  */
extern int wcsncmp (__const wchar_t *__s1, __const wchar_t *__s2, size_t __n)
     __THROW __attribute_pure__;
__END_NAMESPACE_STD

#ifdef __USE_XOPEN2K8
/* Compare S1 and S2, ignoring case.  */
extern int wcscasecmp (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;

/* Compare no more than N chars of S1 and S2, ignoring case.  */
extern int wcsncasecmp (__const wchar_t *__s1, __const wchar_t *__s2,
            size_t __n) __THROW;

/* Similar to the two functions above but take the information from
   the provided locale and not the global locale.  */
# include <xlocale.h>

extern int wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
             __locale_t __loc) __THROW;

extern int wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
              size_t __n, __locale_t __loc) __THROW;
#endif


/* Special versions of the functions above which take the locale to
   use as an additional parameter.  */
extern long int wcstol_l (__const wchar_t *__restrict __nptr,
              wchar_t **__restrict __endptr, int __base,
              __locale_t __loc) __THROW;

extern unsigned long int wcstoul_l (__const wchar_t *__restrict __nptr,
                    wchar_t **__restrict __endptr,
                    int __base, __locale_t __loc) __THROW;

__extension__
extern long long int wcstoll_l (__const wchar_t *__restrict __nptr,
                wchar_t **__restrict __endptr,
                int __base, __locale_t __loc) __THROW;

__extension__
extern unsigned long long int wcstoull_l (__const wchar_t *__restrict __nptr,
                      wchar_t **__restrict __endptr,
                      int __base, __locale_t __loc)
     __THROW;

extern double wcstod_l (__const wchar_t *__restrict __nptr,
            wchar_t **__restrict __endptr, __locale_t __loc)
     __THROW;

extern float wcstof_l (__const wchar_t *__restrict __nptr,
               wchar_t **__restrict __endptr, __locale_t __loc)
     __THROW;

extern long double wcstold_l (__const wchar_t *__restrict __nptr,
                  wchar_t **__restrict __endptr,
                  __locale_t __loc) __THROW;


/* Copy SRC to DEST, returning the address of the terminating L'\0' in
   DEST.  */
extern wchar_t *wcpcpy (wchar_t *__restrict __dest,
            __const wchar_t *__restrict __src) __THROW;

/* Copy no more than N characters of SRC to DEST, returning the address of
   the last character written into DEST.  */
extern wchar_t *wcpncpy (wchar_t *__restrict __dest,
             __const wchar_t *__restrict __src, size_t __n)
     __THROW;
#endif  /* use GNU */


/* Wide character I/O functions.  */

#ifdef  __USE_XOPEN2K8
/* Like OPEN_MEMSTREAM, but the stream is wide oriented and produces
   a wide character string.  */
extern __FILE *open_wmemstream (wchar_t **__bufloc, size_t *__sizeloc) __THROW;
#endif

#if defined __USE_ISOC95 || defined __USE_UNIX98
__BEGIN_NAMESPACE_STD

/* Select orientation for stream.  */
extern int fwide (__FILE *__fp, int __mode) __THROW;


/* Write formatted output to STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fwprintf (__FILE *__restrict __stream,
             __const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
/* Write formatted output to stdout.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int wprintf (__const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wprintf__, 1, 2))) */;
/* Write formatted output of at most N characters to S.  */
extern int swprintf (wchar_t *__restrict __s, size_t __n,
             __const wchar_t *__restrict __format, ...)
     __THROW /* __attribute__ ((__format__ (__wprintf__, 3, 4))) */;

/* Write formatted output to S from argument list ARG.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int vfwprintf (__FILE *__restrict __s,
              __const wchar_t *__restrict __format,
              __gnuc_va_list __arg)
     /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
/* Write formatted output to stdout from argument list ARG.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int vwprintf (__const wchar_t *__restrict __format,
             __gnuc_va_list __arg)
     /* __attribute__ ((__format__ (__wprintf__, 1, 0))) */;
/* Write formatted output of at most N character to S from argument
   list ARG.  */
extern int vswprintf (wchar_t *__restrict __s, size_t __n,
              __const wchar_t *__restrict __format,
              __gnuc_va_list __arg)
     __THROW /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;


/* Read formatted input from STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int fwscanf (__FILE *__restrict __stream,
            __const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
/* Read formatted input from stdin.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern int wscanf (__const wchar_t *__restrict __format, ...)
     /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
/* Read formatted input from S.  */
extern int swscanf (__const wchar_t *__restrict __s,
            __const wchar_t *__restrict __format, ...)
     __THROW /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;

# if defined __USE_ISOC99 && !defined __USE_GNU \
     && (!defined __LDBL_COMPAT || !defined __REDIRECT) \
     && (defined __STRICT_ANSI__ || defined __USE_XOPEN2K)
#  ifdef __REDIRECT
/* For strict ISO C99 or POSIX compliance disallow %as, %aS and %a[
   GNU extension which conflicts with valid %a followed by letter
   s, S or [.  */
extern int __REDIRECT (fwscanf, (__FILE *__restrict __stream,
                 __const wchar_t *__restrict __format, ...),
               __isoc99_fwscanf)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
extern int __REDIRECT (wscanf, (__const wchar_t *__restrict __format, ...),
               __isoc99_wscanf)
     /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
extern int __REDIRECT_NTH (swscanf, (__const wchar_t *__restrict __s,
                     __const wchar_t *__restrict __format,
                     ...), __isoc99_swscanf)
     /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
#  else
extern int __isoc99_fwscanf (__FILE *__restrict __stream,
                 __const wchar_t *__restrict __format, ...);
extern int __isoc99_wscanf (__const wchar_t *__restrict __format, ...);
extern int __isoc99_swscanf (__const wchar_t *__restrict __s,
                 __const wchar_t *__restrict __format, ...)
1 голос
/ 30 июля 2011

Как я предложил в комментарии, вам следует взглянуть на ICU , которая является кроссплатформенной библиотекой C для обработки Unicode, созданной IBM.Он обеспечивает дополнительную поддержку C ++ и Java с очень мощным классом String.Он используется во многих местах, таких как Android и iOS, поэтому он очень стабилен и зрел.

...