Исключить слова, которые могут заканчиваться или не заканчиваться косой чертой

Я пытаюсь исключить определенные слова из файла словаря.

# cat en.txt
test
testing
access/p
batch
batch/n
batches
cross

# cat exclude.txt
test
batch

# grep -vf exclude.txt en.txt
access/p
cross

В результаты должны быть включены такие слова, как «тестирование» и «партии».

expected result:
testing
access/p
batches
cross

Потому что за словом «партия» может следовать или не следовать косая черта «/». После косой черты может быть один или несколько тегов (в данном случае n). Но слово «партии» — это другое слово, и оно не должно совпадать с «партией».

grep -w, кажется, требуется совпадение целых слов, вы пробовали это?
TLP 03.12.2022 10:17

У вас может быть такая строчка, как foo/batch в en.txt? Если да, то должен ли он быть выведен или не с учетом вашего опубликованного exlude.txt? Может ли exclude.txt содержать какие-либо отдельные буквы, такие как n, например, в batch/n?

Ed Morton 03.12.2022 18:48

Если в en.txt есть слово «тест/партия», его не следует включать в результаты. В файле exclude.txt есть только слова без тегов (hunspell).

shantanuo 04.12.2022 06:27

@TLP попробовал параметр -w. Но это не дает правильных результатов, потому что мой файл содержит символы Юникода, а grep не полностью совместим.

shantanuo 04.12.2022 07:34

@shantanuo Возможно, это была довольно важная информация для вашего вопроса. Почему бы вам исключить это?

TLP 04.12.2022 10:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
85
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я бы использовал GNU AWK для этой задачи следующим образом, пусть en.txt контент будет

test
testing
access/p
batch
batch/n
batches
cross

и exclude.txt содержание быть

test
batch

затем

awk 'BEGIN{FS = "/"}FNR==NR{arr[$1];next}!($1 in arr)' exclude.txt en.txt

дает вывод

testing
access/p
batches
cross

Объяснение: я сообщаю GNU AWK, что / является разделителем полей (FS), затем при обработке первого файла (где количество строк глобально равно количеству строк внутри файла, то есть FNR==NR) я просто использую значение 1-го столбца в качестве ключа в массиве arr а затем перейти к строке next, так что больше ничего не происходит, для 2-й (и следующих файлов, если они есть) я выбираю строки, чей 1-й столбец не является (!) одним из ключей массива arr.

(проверено в GNU Awk 5.0.1)

Поскольку в словаре есть много слов, которые могут иметь корень в одном из тех, которые нужно исключить, мы не можем удобно использовать поисковый хеш (построенный из списка исключений), но должны проверять их все. Один из способов сделать это более эффективно — использовать шаблон чередования, построенный на основе списка исключений.

use warnings;
use strict;
use feature 'say';
use Path::Tiny;  # to read ("slurp") a file conveniently

my $excl_file = 'exclude.txt';

my $re_excl = join '|', split /\n/, path($excl_file)->slurp;
$re_excl = qr($re_excl);

while (<>) { 
    if ( m{^ $re_excl (?:/.)? $}x )  {   
        # say "Skip printing (so filter out): $_";
        next;
    }
    say;
}

Это используется как program.pl dictionary-filename и печатает отфильтрованный список.

Здесь я предположил, что за корневым словом для исключения может следовать /, за которым следует один символ, (?:/.)?, так как примеры в вопросе используют это, и по этому поводу нет точного утверждения. Шаблон также предполагает отсутствие пробелов вокруг слова.

Пожалуйста, отрегулируйте по мере необходимости для того, что может на самом деле последовать /. Например, это будет (?:/.+)? хотя бы для одного персонажа, (?:/[np])? для любого персонажа из определенного списка (n или p), (?:[^xy]+)? для любого персонажа, не входящего в данный список, и т. д.

Оператор qr формирует правильный шаблон регулярного выражения.


Может по-прежнему сначала удалять окончания слов, затем использовать поиск, а затем возвращать эти окончания

use Path::Tiny;  # to read a file conveniently

my %lu = map { $_ => 1 } path($excl_file)->lines({ chomp => 1 });

while (<>) { 
    chomp;

    # [^\w-] protects hyphenated words (or just use \W)
    # Or: s{(/.+$}{}g;  if "/" is the only possibility
    s/([^\w-].+)$//g;

    next if exists $lu{$_};

    $_ .= $1 if $1; 
    say;
}

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

Однако это гораздо сложнее и, вероятно, не соответствует некоторым (неустановленным) требованиям.

Ответ принят как подходящий

Используя grep, сопоставляющий целые слова:

grep -wvf exclude.txt en.txt

Объяснение (от man grep)

  • -w--word-regexp Выберите только те строки, которые содержат совпадения, образующие целые слова.
  • -v--invert-match Инвертируйте смысл совпадения, чтобы выбрать несовпадающие строки.
  • -f-f FILE Получить шаблоны из ФАЙЛА, по одному в строке.

Вывод

testing
access/p
batches
cross

попробовал параметр -w. Но это не дает правильных результатов, потому что мой файл содержит символы Юникода, а grep не полностью совместим. Но rg (ripgrep), похоже, работает как положено. Я не упомянул о нелатинских символах, когда спрашивал, потому что не думал, что это будет иметь какое-то значение.

shantanuo 04.12.2022 07:36

Другие вопросы по теме