Я хотел бы знать, является ли следующее поведение надежным:
echo 😄 | gawk '{split($0,array,"."); print array[1] length(array);}'
Вывод: 😄1
против
echo 😄 | gawk '{patsplit($0,array,"."); print array[1] length(array);}'
Вывод: �4
patsplit
работает над байтами, а split
над символами, но я нигде не нашел этого задокументированного или обсуждаемого. Вопрос в том, могу ли я рассчитывать на такое поведение и где?
Это потому, что split
и patsplit
— принципиально разные функции.
split
делит строку на поля с помощью разделителя полей, т. е. того, что находится между полями, а patsplit
делит строку на поля, сопоставляя сами поля с шаблоном поля.
Все функции gawk, включая split
и patsplit
, работают с зависящими от локали символами, а не с байтами, согласно документации .
Кроме того, односимвольная строка, такая как "."
, в качестве разделителя полей рассматривается буквально, а не как шаблон регулярного выражения (см. документацию по FS
).
Поскольку во входной строке 😄 нет .
, при вызове split
с "."
в качестве разделителя полей split
видит только 1 поле.
А поскольку 😄 состоит из 4 байтов и, предположительно, вы установили локаль на основе байтов, например C
, когда вы вызываете patsplit
с "."
в качестве шаблона поля, каждый .
соответствует одному байту 😄, создавая массив размером 4.
Пожалуйста, проверьте связанную документацию, где говорится: «Gawk понимает локали (см. Где вы находитесь, имеет значение) и выполняет всю обработку строк в виде символов, а не байтов». Объявление C может быть char *s;
, если оно обрабатывается как символы с учетом локали.
Я это читал, но похоже, что это неправда.
Опять же, тот факт, что тип параметра равен char *
, не означает, что он логически обрабатывается побайтно. Если вы будете следовать коду, вы увидите, что он вызывает fpat_parse_field
, который, в свою очередь, вызывает research
, который обрабатывает строку как символы со всеми вспомогательными функциями, поддерживающими LC, в regcomp.c
.
Да, я думаю, это последовательно. Я переключил разделитель разделения на пустую строку ""
, и оба возвращают количество байтов с помощью LC_ALL=C и количество символов с помощью LC_ALL=en_US.UTF-8. Возможно, документация могла бы прояснить ситуацию.
Я не думаю, что документация должна быть более понятной, поскольку, заявляя, что все строки обрабатываются как символы с учетом локали, а не как байты, уже установлено, что символы эквивалентны байтам, когда вы устанавливаете LC_CTYPE
как C
(который принадлежит документации локали).
Если у вас есть многобайтовый символ и для LC_ALL установлено значение C, вы читаете байты в этот момент. Это семантический танец, в документации, вероятно, отражена поддержка многобайтовых символов как запоздалая мысль.
скорее всего, это ошибка со стороны gawk
.
Я прочитал
fieldsep, is a regexp describing where to split string
о разделении из документа GNU. Не знаю, почему документ говорит, что он работает с символами, символ 😄, состоящий из 1 символа и 4 байтов. Я проверил src, в поле field.c в do_patsplit вы можете увидеть, что он объявленchar *s;
, что составляет байты.