Я пытаюсь написать регулярное выражение, которое будет отображать все слова длиной 10 символов, и ни одна из букв не повторяется.
Пока у меня есть
grep --colour -Eow '(\w{10})'
Что является самой первой частью вопроса. Как бы я проверил «уникальность»? Я действительно понятия не имею, кроме этого мне нужно использовать обратные ссылки.
grep
regular-expression
Дилан Миус
источник
источник
Ответы:
исключает слова, которые имеют два одинаковых символа.
исключая те, которые имеют повторяющиеся символы.
POSIXly:
tr
помещает слова в отдельную строку, преобразовывая все sсимволы, не входящие в состав слова ( cпропуска букв, цифр и подчеркивания), в символ новой строки.Или с одним
grep
:(за исключением строк длиной менее 10 и более 10 символов, а также строк, в которых символы появляются как минимум дважды).
grep
Только с одним (GNU grep с поддержкой PCRE илиpcregrep
):Таким образом, за границей слова (
\b
) следует последовательность из 10 символов слова (при условии, что за каждым не следует последовательность символов слова и сами по себе, используя оператор PCRE с отрицательным прогнозом(?!...)
).Нам повезло, что это работает здесь, так как не многие движки регулярных выражений работают с обратными ссылками внутри повторяющихся частей.
Обратите внимание, что (по крайней мере, с моей версией GNU grep)
Не работает, но
делает (как
echo aa | grep -Pw '(.)\2'
), что звучит как ошибка.Вы можете хотеть:
если вы хотите
\w
или\b
считаете любую букву компонентом слова, а не только буквы ASCII в не-ASCII локалях.Другая альтернатива:
Это граница слова (за которой не следует последовательность символов слова, один из которых повторяется), за которой следуют 10 символов слова.
Вещи, которые могут быть в глубине души:
Babylonish
что, например, будет совпадать, так как все символы различны, даже если есть дваB
s, один нижний и один верхний регистр (используйте-i
для изменения этого).-w
,\w
и\b
, слово это буква (ASCII те только для GNUgrep
сейчас , то[:alpha:]
класс символов в вашей местности при использовании-P
и(*UCP)
), десятичных цифр или подчеркивания .c'est
(два слова согласно французскому определению слова) илиit's
(одно слово согласно некоторым английским определениям слова) илиrendez-vous
(одно слово согласно французскому определению слова) не считаются одним словом.(*UCP)
символы объединения Юникод не рассматриваются как компоненты слова, поэтомуtéléphone
($'t\u00e9le\u0301phone'
) считается как 10 символов, один из которых не альфа.défavorisé
($'d\u00e9favorise\u0301'
) будет совпадать, даже если у него два,é
потому что это 10 разных буквенных символов, за которыми следует сочетание острого акцента (не альфа, поэтому между словомe
и его акцентом есть граница слова ).источник
\w
не совпадает,-
хотяХорошо ... вот неуклюжий способ для строки из пяти символов:
Поскольку вы не можете поместить обратную ссылку в класс символов (например
[^\1|\2]
), вы должны использовать отрицательный прогноз -(?!foo)
. Это функция PCRE, поэтому вам нужен-P
переключатель.Конечно, шаблон для строки из 10 символов будет намного длиннее, но есть более короткий метод, использующий переменную длину, совпадающую с любым ('. *') В запросе:
Прочитав поучительный ответ Стефана Чазела, я понял, что есть аналогичный простой шаблон для использования с помощью
-v
переключателя grep :Так как проверка выполняется по одному символу за раз, будет видно, сопровождается ли после любого заданного символа ноль или более символов (
.*
), а затем совпадение для обратной ссылки.-v
инвертирует, печатая только то, что не соответствует этому шаблону. Это делает обратные ссылки более полезными, так как они не могут быть отменены классом символов, и значительно:будет работать для идентификации строки любой длины с уникальными символами, тогда как:
не будет, так как он будет сопоставлять любой суффикс с уникальными символами (например,
abcabc
совпадения из-заabc
конца иaaaa
из-заa
конца - отсюда и любая строка). Это осложнение вызвано тем, что обходные пути имеют нулевую ширину (они ничего не потребляют).источник
(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!\4).
Если вам не нужно делать все это в регулярном выражении, я бы сделал это в два этапа: сначала сопоставьте все 10-буквенные слова, затем отфильтруйте их по уникальности. Самый короткий способ, которым я знаю, как это сделать, в Perl:
Обратите внимание на дополнительные
\W
привязки, чтобы гарантировать, что сопоставляются только слова длиной ровно 10 символов.источник
Другие предположили, что это невозможно без различных расширений некоторых систем регулярных выражений, которые на самом деле не являются регулярными. Тем не менее, поскольку язык, который вы хотите использовать, является конечным, он явно регулярный. Для 3 букв из 4-буквенного алфавита это будет легко:
Очевидно, что это выходит из-под контроля в спешке с большим количеством букв и больших алфавитов. :-)
источник
Опция
--perl-regexp
(краткая-P
) GNUgrep
использует более мощные регулярные выражения, которые включают в себя шаблоны заблаговременного просмотра. Следующий шаблон ищет каждую букву, которую эта буква не встречает в оставшейся части слова:Однако поведение во время выполнения довольно плохое, потому что
\w*
может иметь почти бесконечную длину. Это может быть ограничено\w{,8}
, но это также проверяет превышение предела в 10 букв. Поэтому следующий шаблон сначала проверяет правильную длину слова:В качестве тестового файла я использовал большой файл размером 500 МБ:
Обновить:
Я не смог найти существенного изменения в поведении во время выполнения для не жадного оператора (
\w*?
) или притяжательного оператора ((...){10}+
). Немного быстрее кажется замена опции-w
:Обновление grep с версии 2.13 до 2.18 было намного более эффективным. Тестовый файл занял ≈ 6 с.
источник
\w{,8}?
) помогло для некоторого типа ввода (хотя и не очень значительно). Хорошее использование,\g{-1}
чтобы обойти ошибку GNU grep.\g{-1}
, потому что это делает шаблон более независимым от местоположения. В этой форме это может использоваться как часть большего образца.Решение Perl:
но это не работает с
или
протестировано с Perl v5.14.2 и v5.18.2
источник