Я хочу знать, как использовать grep
для отображения всех строк, которые начинаются и заканчиваются одним и тем же символом.
Я хочу знать, как использовать grep
для отображения всех строк, которые начинаются и заканчиваются одним и тем же символом.
Ответы:
POSIXly:
pattern='\(.\).*\1
.'
grep -x -- "$pattern" file
Это не будет работать, если строка начинается или заканчивается недействительным байтовым символом, если вы хотите охватить этот случай, вы можете добавить LC_ALL=C
, хотя LC_ALL=C
работает только с однобайтовыми символьными данными.
perl6
кажется лучшим инструментом, если он у вас в коробке:
$ printf '\ue7\u301 blah \u107\u327\n121\n1\n123\n' |
perl6 -ne '.say if m/^(.).*$0$/ || /^.$/'
ḉ blah ḉ
121
1
Хотя это все еще задыхается от недопустимых символов.
Обратите внимание, что perl6
изменит ваш текст, превратив его в NFC
форму:
$ printf '\u0044\u0323\u0307\n' |
perl6 -pe '' |
perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+1e0c
U+0307
U+000a
$ printf '\u0044\u0323\u0307\n' |
perl -pe '' |
perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+0044
U+0323
U+0307
U+000a
Внутри perl6
хранится строка в NFG
форме (обозначать Normalization Form Grapheme
), которая perl6
придумана для правильной работы с предварительно не скомпонованными графемами:
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.chars.say'
1
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.codes.say'
2
perl6
изменит текст, хотя (превратить его в NFC (нормализованная форма "составлено")).
perl6
- это store in NFG
form ( G
for Grapheme
), что позволяет perl6
правильно обрабатывать нескомпонованные графемы.
Не grep, а awk:
awk -F "" 'NF && $1 == $NF'
Эти особые случаи обрабатываются:
Пустой FS разделяет запись на один символ на поле в gawk
, mawk
и busybox
awk
(байты, а не символы для последних двух), но не является стандартным и не работает в реализациях, awk
производных от исходного A, W и K, как на BSDs и коммерческих единицах. Более портативный, но больше для ввода:
awk '/./ && substr($0,1,1) == substr($0,length)'
FS
пустая строка не является стандартной и не будет работать в некоторых awk
реализациях.
awk 'length&&substr($0,1,1)==substr($0,length)'
(обратите внимание, что по умолчанию используется аргумент length
is $0
, а действие по умолчанию is {print $0}
)
nawk
почти так же плохо :-)
grep -xe '\(.\).*\1' -e .
Пример:
$ printf '%s\n' il y était cet été | grep -xe '\(.\).*\1' -e .
y
été
-x
для точного соответствия (совпадение по всей строке). \1
являясь обратной ссылкой на персонажа, захваченного в \(.\)
. Мы добавляем a, -e .
чтобы позаботиться о специальном случае строки, содержащей один единственный символ.
Предполагается, что ввод содержит действительный текст в текущей локали.
Соответствие идет по символу , а не по байту (например, é в UTF-8 - это два байта 0xc3 0xa9), или кластер graphem (он не будет работать, если эти é были записаны в разложенном виде с e
последующим U + 0301 например, сочетая острый акцент).
Для работы на кластерах графема с grep
поддержкой -P
PCRE:
$ printf 'e\u0301te\u0301\n' | grep -xPe '(\X).*\1|\X'
été
При этом предполагается, что разложение является одинаковым для двух кластеров, например, ḉ
выражение, c
U+0301
U+0327
которое не соответствует, выражается как c
U+0327
U+0301
или ć
( U+0107
) U+0327
или ç
( U+00E7
) U+0301
или ḉ ( U+1E09
). Для этого вам необходимо выполнить проверку в нормализованной форме:
$ printf '\ue7\u301 blah \u107\u327\n' |
perl -MUnicode::Normalize -C -ne '
print if /^\X$/ || NFC($_) =~ /^(\X).*\1$/'
ḉ blah ḉ
perl6
, то perl6 -ne '.say if m/^(.).*$0$/ || /^.$/'
должны сделать все работы за вас.
Быстрая альтернатива python2:
python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt
Пример:
$ python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt | cat -A
nathan$
ookie $
a line a$