Соответствующая строка с фиксированным количеством символов с использованием grep

9

Я пытаюсь найти все 6буквенные слова, используя grep. В настоящее время у меня есть это:

grep "^.\{6\}$" myfile.txt 

Тем не менее, я обнаружил, что я также получаю такие результаты, как: étuis, étude.

Я подозреваю, что это как-то связано с символами над eприведенными выше словами.

Могу ли я что-нибудь сделать, чтобы этого не произошло?

Спасибо за вашу помощь!


источник

Ответы:

4

grepИдея персонажа зависит от локали . Если вы находитесь в локали, отличной от Unicode, и выполняете поиск в файле с символами Unicode, тогда количество символов не будет совпадать. Если вы, echo $LANGто увидите локаль, в которой находитесь.

Если вы установите для переменных среды окружения LC_CTYPEи / или LANGзначение, заканчивающееся на «.UTF-8», то вы получите правильное поведение:

$ cat data
étuis
letter
éééééé
$ LANG=C grep -E '^.{6}$' data
étuis
letter
$ LANG=en_US.UTF_8 grep -E '^.{6}$' data
letter
éééééé
$

Вы можете изменить свой язык только для одной команды, назначив переменную в той же строке, что и команда.

В этой конфигурации многобайтовые символы рассматриваются как отдельные символы. Если вы хотите полностью исключить символы, не входящие в ASCII, у некоторых других ответов есть решения для вас.


Обратите внимание, что все еще возможно что-то сломать или, по крайней мере, сделать не совсем то, что вы ожидаете, при наличии комбинированных символов . Вы grepможете рассматривать ЛАТИНСКОЕ МАЛЕНЬКОЕ ПИСЬМО E + КОМБИНИРУЮЩИЙ ХАРАКТЕР ОСТРОГО выше, чем ЛАТИНСКОЕ МАЛЕНЬКОЕ ПИСЬМО Е С ОСТРЫМ.

Майкл Гомер
источник
если вы используете ., что-то вроде wăsd'sбудет соответствовать
cuonglm
'символ, который может быть разумно частью «строки с фиксированным количеством символов».
Майкл Гомер
Может быть. И вы должны установить оба, LC_CTYPEи LANG, что-то подобное LC_CTYPE=en_US.UTF-8 LANG=en_USне удастся. Используйте LC_ALLдля безопасности.
cuonglm
2

Попробуй это:

LC_ALL=C.UTF-8 grep -x '[_[:alnum:]]\{6\}' file

-x использовать для сопоставления всей строки и определяется POSIX (см. grep ).

Смотрите здесь для хорошего объяснения того, что LC_ALLделает. Вы можете установить LANGили LC_CTYPEиспользовать utf-8, чтобы получить то же поведение. Эффект принятия заказа: LC_ALL=> LANG=> LC_CTYPE.

cuonglm
источник
2

С GNU grepпри поддержке PCRE вы можете делать:

grep -Px '\X{6}'

Пока .соответствует персонажу,\X соответствует идеограмме / графему.

В стандарте UTF-8:

$ locale charmap
UTF-8
$ printf '\u00e9tuis\n\u00e9tudes\n' | grep -Px '\X{6}'
études
$ printf 'e\u0301tuis\ne\u0301tudes\n' | grep -Px '\X{6}'
études

В последнем étudesесть 7 символов, 8 байтов и 6 графем.

Стефан Шазелас
источник
Кажется , не работает: echo épée | grep -Px '\X{6}'Ouputépée
cuonglm
@ Gnouc, вам нужно запустить это в локали UTF-8 (если éвышеперечисленные были закодированы в UTF-8).
Стефан Шазелас
Ох, мои ошибки. Работает с UTF-8.
cuonglm
0

Вы можете попробовать что-то вроде:

grep "^[A-Za-z]\{6\}$" myfile.txt

или если слова тоже могут содержать числа, то:

grep "^[A-Za-z0-9]\{6\}$" myfile.txt

Просто добавьте любые символы в квадратные скобки, которые вы хотите в дополнение к этим.

Warwick
источник
Это не будет соответствовать étudeвообще, потому что символ ASCII, соответствующий акценту, испортит регулярное выражение.
Алекс