Как обработать строку char символом в коде XS
Давайте предположим, что есть такой код:
my $str = 'some text';
my $result = my_subroutine($str);
а также my_subroutine()
должен быть реализован в виде кода Perl XS. Например, он может вернуть сумму байтов строки (Unicode).
В коде XS, как обрабатывать строку (a) char за char, как общий метод, и (b) byte byte, если строка состоит из подмножества кодов ASCII (встроенная функция для преобразования из нативного структура данных строки в char[])?
2 ответа
На уровне XS вы получите байты или строки UTF-8. В общем случае ваш код, скорее всего, будет содержать char *
чтобы указать на следующий элемент в строке, увеличивая его, как он идет. Для получения полезного набора функций поддержки UTF-8 для использования в XS прочитайте раздел "Поддержка Unicode" в perlapi
Пример моего из http://cpansearch.perl.org/src/PEVANS/Tickit-0.15/lib/Tickit/Utils.xs
int textwidth(str)
SV *str
INIT:
STRLEN len;
const char *s, *e;
CODE:
RETVAL = 0;
if(!SvUTF8(str)) {
str = sv_mortalcopy(str);
sv_utf8_upgrade(str);
}
s = SvPV_const(str, len);
e = s + len;
while(s < e) {
UV ord = utf8n_to_uvchr(s, e-s, &len, (UTF8_DISALLOW_SURROGATE
|UTF8_WARN_SURROGATE
|UTF8_DISALLOW_FE_FF
|UTF8_WARN_FE_FF
|UTF8_WARN_NONCHAR));
int width = wcwidth(ord);
if(width == -1)
XSRETURN_UNDEF;
s += len;
RETVAL += width;
}
OUTPUT:
RETVAL
Вкратце, эта функция повторяет заданную строку по одному символу Unicode за раз, накапливая ширину, как wcwidth()
,
Если вы ожидаете байтов:
STRLEN len;
char* buf = SvPVbyte(sv, len);
while (len--) {
char byte = *(buf++);
... do something with byte ...
}
Если вы ожидаете текст или любые не байтовые символы:
STRLEN len;
U8* buf = SvPVutf8(sv, len);
while (len) {
STRLEN ch_len;
UV ch = utf8n_to_uvchr(buf, len, &ch_len, 0);
buf += ch_len;
len -= ch_len;
... do something with ch ...
}