Предоставляет ли POSIX regex.h символы Unicode или символы, не являющиеся ascii? - PullRequest
8 голосов
/ 04 января 2012

Привет, я использую стандартную библиотеку регулярных выражений (regcomp, regexec ..). Но теперь по требованию я должен добавить поддержку юникода в мои коды для регулярных выражений.

Предоставляет ли стандартная библиотека Regex символы Unicode или символы, не являющиеся ascii? Я исследовал в Интернете, и думаю, что нет.

Мой проект является критиком ресурсов, поэтому я не хочу использовать для него большие библиотеки (ICU и Boost.Regex).

Любая помощь будет оценена ..

Ответы [ 3 ]

7 голосов
/ 04 января 2012

Похоже, POSIX Regex работает правильно с языком UTF-8. Я только что написал простой тест (см. Ниже) и использовал его для сопоставления строки с символами кириллицы и регулярного выражения "[[:alpha:]]" (например). И все работает просто отлично.

Примечание: Главное, что вы должны помнить - функции регулярных выражений связаны с локалью. Таким образом, вы должны позвонить setlocale() до этого.

#include <sys/types.h>
#include <string.h>
#include <regex.h>
#include <stdio.h>
#include <locale.h>

int main(int argc, char** argv) {
  int ret;
  regex_t reg;
  regmatch_t matches[10];

  if (argc != 3) {
    fprintf(stderr, "Usage: %s regex string\n", argv[0]);
    return 1;
  }

  setlocale(LC_ALL, ""); /* Use system locale instead of default "C" */

  if ((ret = regcomp(&reg, argv[1], 0)) != 0) {
    char buf[256];
    regerror(ret, &reg, buf, sizeof(buf));
    fprintf(stderr, "regcomp() error (%d): %s\n", ret, buf);
    return 1;
  }

  if ((ret = regexec(&reg, argv[2], 10, matches, 0)) == 0) {
    int i;
    char buf[256];
    int size;
    for (i = 0; i < sizeof(matches) / sizeof(regmatch_t); i++) {
      if (matches[i].rm_so == -1) break;
      size = matches[i].rm_eo - matches[i].rm_so;
      if (size >= sizeof(buf)) {
        fprintf(stderr, "match (%d-%d) is too long (%d)\n",
                matches[i].rm_so, matches[i].rm_eo, size);
        continue;
      }
      buf[size] = '\0';
      printf("%d: %d-%d: '%s'\n", i, matches[i].rm_so, matches[i].rm_eo,
             strncpy(buf, argv[2] + matches[i].rm_so, size));

    }
  }

  return 0;
}

Пример использования:

$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
... (skip)
LC_ALL=
$ ./reg '[[:alpha:]]' ' 359 фыва'
0: 5-7: 'ф'
$

Длина результата сопоставления составляет два байта, потому что кириллические буквы в UTF-8 занимают так много.

6 голосов
/ 04 января 2012

По сути, регулярные выражения POSIX не поддерживают Unicode.Вы можете попытаться использовать их для символов Unicode, но могут быть проблемы с глифами, имеющими несколько кодировок, и другие проблемы, которые библиотеки Unicode обрабатывают для вас.2008 :

Сопоставление должно основываться на битовой комбинации, используемой для кодирования символа, а не на графическом представлении символа.Это означает, что если набор символов содержит два или более кодировок для графического символа или если искомые строки содержат текст, закодированный в более чем одном наборе кодов, не предпринимается никаких попыток поиска какого-либо другого представления кодированного символа.Если это требуется, пользователь может указать классы эквивалентности, содержащие все варианты требуемого графического символа.

Может быть, libpcre будет работать для вас?Это немного тяжелее, чем регулярные выражения POSIX, но я думаю, что это легче, чем ICU или Boost.

0 голосов
/ 05 января 2012

Если вы действительно имеете в виду «Стандарт», то есть std::regex из C ++ 11, то все, что вам нужно сделать, это переключиться на std::wregex (и, конечно, std::wstring).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...