GNU grep и русские буквы (помогите новичку разобраться)

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: GNU grep и русские буквы

Сообщение eddy »

SLEDopit писал(а):
10.03.2011 16:55
egrep, кстати, тоже ведет себя как sed:

А аж задумался: может, у меня grep и есть grep -E, ан нет:

Код: Выделить всё

alias grep='grep --color'

Странно это, что grep ведет себя в разных версиях и на разных локалях совершенно по-разному.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
t.t
Бывший модератор
Сообщения: 7390
Статус: думающий о вечном
ОС: Debian, LMDE

Re: GNU grep и русские буквы

Сообщение t.t »

SLEDopit писал(а):
10.03.2011 16:55
/dev/random писал(а):
10.03.2011 14:37
grep здесь соответствует стандарту, зато sed ведёт себя так, как хотелось бы большинству составителей скриптов.
egrep, кстати, тоже ведет себя как sed:

Код: Выделить всё

 $ echo $LANG
en_US.UTF-8
 $ echo AaBbCc | egrep -o "[a-z]"
a
b
c
 $ echo AaBbCc | egrep -o "[A-Z]"
A
B
C
 $ echo abc | egrep -o "[A-Z]"

Не egrep, а grep -o:

Код: Выделить всё

$ echo b | egrep [A-C]
b
$ echo b | egrep -o [A-C]
$ echo b | grep -o [A-C]
$


Можно, конечно, писать что-то вроде grep -o '.*[A-C].*', но ведь костыль.
¡иɯʎdʞ ин ʞɐʞ 'ɐнɔɐdʞǝdu qнεиж
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: GNU grep и русские буквы

Сообщение SLEDopit »

t.t писал(а):
10.03.2011 16:57
У меня почти чистый stable.
Хм.

Код: Выделить всё

 $ grep -V; locale
GNU grep 2.6.3

Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

 $ echo b | LC_COLLATE=C grep [A-C]

 $ echo b | LC_ALL=C grep [A-C]

 $ cat /etc/issue
Debian GNU/Linux wheezy/sid \n \l
что не так? (:
t.t писал(а):
10.03.2011 17:04
Не egrep, а grep -o:
Да, действительно это из опции -о.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

Судя по нижеследующему, grep (в некоторых версиях и сборках; Debian Squeeze), просто игнорирует системную локаль, а действует исходя только из своих представлений о символах:
# echo hello |LC_COLLATE=es_US sed -n '/e[k-m]o/p'
hello
# echo hello |LC_COLLATE=es_US grep 'e[k-m]o'
#
Баг это, фича, особенность поведения, решать не берусь…
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

http://savannah.gnu.org/bugs/?29820 — рассматривался баг with collating element in grep-2.6.3. Закрыт, а ошибка, якобы была в glibc и уже исправлена.
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

Что-то стало чуть-чуть понятным.
В стандартной библиотеке C просто нет функций, которые позволили бы развернуть [a-z] в набор символов, которые удовлетворяют этому регулярному выражению.
Приходится использовать функцию wcscoll, которая сравнивает строки (учитывая LC_COLLATE). При таком сравнении, естественно, оказывается, что строка L"B\0" больше строки L"a\0", но меньше строки L"z\0".
Вот фрагмент исходного кода (lib/regexec.c):

Код: Выделить всё

 /* match with range expression?  */
#if __GNUC__ >= 2 && ! (__STDC_VERSION__ < 199901L && __STRICT_ANSI__)
      wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
#else
      wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
      cmp_buf[2] = wc;
#endif
      for (i = 0; i < cset->nranges; ++i)
        {
          cmp_buf[0] = cset->range_starts[i];
          cmp_buf[4] = cset->range_ends[i];
          if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
          && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
        {
          match_len = char_len;
          goto check_node_accept_bytes_match;
        }
        }


Почему оказывается, что большие буквы идут после малых — пока это остается загадкой?
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

Попробовал посмотреть на sed, казалось бы, все должно работать так же, если собирать с --with-included-regex, ведь в lib/regexec.c есть аналогичный фрагмент, где вызывается wcscoll.
Запустил в отладчике.

$ echo привет HELLO | sed -n '/[цa-z]/p'
Строка печатается, но тут sed как-то обходится без вызовов wcscoll. Какие-то оптимизации, что-ли?

$ echo привет HELLO | sed -n '/[цa-z]*/p'
а тут все так же, как и в grep.
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: GNU grep и русские буквы

Сообщение sash-kan »

eddy писал(а):
10.03.2011 16:12
[на правах офтопа]
И несмотря на все эти "косяки", мне все равно советуют сменить "динозавра" КОИ8-Р на юникод smile.gif
[/на правах офтопа]
а вы как хотели? чем меньше однобайтовых динозавров останется в природе (ох уж эта мне америка), тем быстрее будут устраняться (возможные) ошибки в glibc.
а пока динозавров слишком много (ох уж эта мне америка) — нет-нет да и проскакивают динозавро-баги.
удачи вам, однобайтовые! (ох уж эта мне америка).

Nazyvaemykh писал(а):
12.03.2011 10:45
$ echo привет HELLO | sed -n '/[цa-z]*/p'
а тут все так же, как и в grep.
гхм. не понял смысла этого regexp-а. он же совпадёт в любом случае.


Nazyvaemykh писал(а):
12.03.2011 10:45
$ echo привет HELLO | sed -n '/[цa-z]/p'
Строка печатается
как это «печатается»? находится совпадение? значит, у вас там баг какой-то сидит.
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

sash-kan писал(а):
12.03.2011 16:10
Nazyvaemykh писал(а):
12.03.2011 10:45
$ echo привет HELLO | sed -n '/[цa-z]*/p'
а тут все так же, как и в grep.
гхм. не понял смысла этого regexp-а. он же совпадёт в любом случае.

Н-да, ошибку давал… Что-то меня дернуло подумать, что [цa-z]* это [цa-z]\+
Nazyvaemykh писал(а):
12.03.2011 10:45
$ echo привет HELLO | sed -n '/[цa-z]/p'
Строка печатается
как это «печатается»? находится совпадение? значит, у вас там баг какой-то сидит.

Вот в том-то и дело, что не баг это, а фича. Как в grep, так и в sed.
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: GNU grep и русские буквы

Сообщение sash-kan »

Nazyvaemykh писал(а):
12.03.2011 17:47
QUOTE писал(а):
Nazyvaemykh писал(а):
12.03.2011 10:45
$ echo привет HELLO | sed -n '/[цa-z]/p'
Строка печатается
как это «печатается»? находится совпадение? значит, у вас там баг какой-то сидит.

Вот в том-то и дело, что не баг это, а фича. Как в grep, так и в sed.
этот _баг_ мне удалось воспроизвести лишь на какой-то древнючей системе. в актуальных дистрибутивах
$ echo привет HELLO | sed -n '/[цa-z]/p' | wc -l
выдаёт 0.
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

У меня так ведет себя GNU sed 4.2.1, собранный с опцией --with-included-regex. Вот вы, sash-kan, как sed собираете?
Аналогичное поведение grep подтверждено и другими участниками форума.

Это не баг, это фича. Повторю сказанное в #36.
Ни у sed, ни у grep нет возможности проверить вхождение символа в диапазон, иначе как вызывая стандартную функцию wcscoll (если они не используют внешнюю библиотеку регулярных выражений, которая есть не во всех системах).
А согласно этой функции, строка L"B\0" лексикографически меньше строки L"c\0", но больше строки L"a\0".
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: GNU grep и русские буквы

Сообщение SLEDopit »

Nazyvaemykh писал(а):
12.03.2011 20:08
Вот вы, sash-kan, как sed собираете?
Зуб даю, что вот так:

Код: Выделить всё

$ sudo aptitude install sed
(:
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: GNU grep и русские буквы

Сообщение sash-kan »

SLEDopit писал(а):
12.03.2011 20:15
Зуб даю, что вот так
естественно. потому _багов_ и не наблюдаю.

p.s. ещё yum install sed, urpmi sed и т.п.
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: GNU grep и русские буквы

Сообщение drBatty »

Nazyvaemykh писал(а):
11.03.2011 13:37
В стандартной библиотеке C просто нет функций, которые позволили бы развернуть [a-z] в набор символов, которые удовлетворяют этому регулярному выражению.

за то есть

Код: Выделить всё

       int regcomp(regex_t *preg, const char *regex, int cflags);

       int regexec(const regex_t *preg, const char *string, size_t nmatch,
                   regmatch_t pmatch[], int eflags);

       size_t regerror(int errcode, const regex_t *preg, char *errbuf,
                       size_t errbuf_size);

       void regfree(regex_t *preg);

которые [a-z] понимают (хотя не понимают [а-я] в юникоде).
Nazyvaemykh писал(а):
12.03.2011 10:45
если собирать с --with-included-regex

насколько я знаю, так имеет смысл собирать только в версии для Windows.

sash-kan писал(а):
13.03.2011 16:58
ещё yum install sed, urpmi sed

installpkg sed
для слаки.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: GNU grep и русские буквы

Сообщение sash-kan »

drBatty писал(а):
13.03.2011 17:37
installpkg sed
для слаки.
не-не-не. никаких installpkg/emerge/etc. максимум — opkg install sed.

p.s. забыл про zypper in sed
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
Nazyvaemykh
Сообщения: 438
Статус: Подопытный участник

Re: GNU grep и русские буквы

Сообщение Nazyvaemykh »

Вы, ребята, молодцы, но вот кто и как собирал grep в Squeeze, что он столь неожиданно матчит…
¡ Страсть к разрушению есть творческая страсть!
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: GNU grep и русские буквы

Сообщение drBatty »

/dev/random писал(а):
10.03.2011 14:37
Ну что тут сказать... grep здесь соответствует стандарту, зато sed ведёт себя так, как хотелось бы большинству составителей скриптов. Формально это баг sed, но, полагаю, что они (да и я, наверное, тоже) назовут это фичой. Надо посмотреть, есть ли это у них в документации.

подождите! но почему [a-z] должно-бы регистро-независимым в данной локали?!

Код: Выделить всё

ksu@ksu:~/test$ echo HELLO | LC_COLLATE=en_US.UTF-8 sed -n '/[a-z]/p'
ksu@ksu:~/test$ echo HELLO | LC_COLLATE=en_US.UTF-8 sed -n '/[a-z]/Ip'
HELLO

Как и сказано в документации, сравнение регистро-независимо с опцией I (для s/// опция i маленькая)
с русским тоже всё работает.

Код: Выделить всё

ksu@ksu:~/test$ echo ФФФФ | LC_COLLATE=ru_RU.UTF-8 sed -n '/[а-я]/Ip'
ФФФФ
ksu@ksu:~/test$ echo ФФФФ | LC_COLLATE=ru_RU.UTF-8 sed -n '/[а-я]/p'
ksu@ksu:~/test$

не понял, что тут не соответствует?

Nazyvaemykh писал(а):
14.03.2011 18:04
Вы, ребята, молодцы, но вот кто и как собирал grep в Squeeze, что он столь неожиданно матчит…


маинтейнеры сквиза. а в чём неожиданность-то? в том, что grep иногда путает малые и большие буквы? ну с кем не бывает? (:
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: