Совпадение строк из двух списков с подстановочными знаками в одном списке - PullRequest
1 голос
/ 31 мая 2019

У меня есть два списка, один из которых содержит символы подстановки (в данном случае представлены *). Я хотел бы сравнить два списка и создать выходные данные из тех, которые совпадают, с каждым подстановочным знаком *, представляющим один символ.

Например:

Файл 1

123456|Jane|Johnson|Pharmacist|janejohnson@gmail.com
09876579|Frank|Roberts|Butcher|frankie1@hotmail.com
092362936|Joe|Jordan|Joiner|joe@joesjoinery.com
928|Bob|Horton|Farmer|bhorton@farmernews.co.uk

Файл 2

1***6|Jane|Johnson|Pharmacist|janejohnson@gmail.com
09876579|Frank|Roberts|Butcher|f**1@hotmail.com
092362936|Joe|Jordan|J*****|joe@joesjoinery.com
928|Bob|Horton|Farmer|b*****n@f*********.co.uk

выход

092362936|Joe|Jordan|Joiner|joe@joesjoinery.com
928|Bob|Horton|Farmer|bhorton@farmernews.co.uk

Объяснение

Первые две строки не считаются совпадениями, поскольку число * s не равно количеству символов, показанных в первом файле. Последние два, поэтому они добавляются к выводу.

Я пытался обдумать способы сделать это в AWK и использовать Join, но я не знаю никакого способа даже начать пытаться добиться этого. Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

2 голосов
/ 01 июня 2019
$ cat tst.awk
NR==FNR {
    file1[$0]
    next
}
{
    # Make every non-* char literal (see https://stackoverflow.com/a/29613573/1745001):
    gsub(/[^^*]/,"[&]")  # Convert every char X to [X] except ^ and *
    gsub(/\^/,"\\^")     # Convert every ^ to \^

    # Convert every * to .:
    gsub(/\*/,".")

    # Add line start/end anchors
    $0 = "^" $0 "$"

    # See if the current file2 line matches any line from file1
    # and if so print that line from file1:
    for ( line in file1 ) {
        if ( line ~ $0 ) {
            print line
        }
    }
}

$ awk -f tst.awk file1 file2
092362936|Joe|Jordan|Joiner|joe@joesjoinery.com
928|Bob|Horton|Farmer|bhorton@farmernews.co.uk
0 голосов
/ 31 мая 2019
sed 's/\./\\./g; s/\*/./g' file2 | xargs -I{} grep {} file1

Пояснение:

Я бы воспользовался соответствием регулярного выражения. Для этого нам нужно превратить каждую звездочку * в точку ., которая представляет любой символ в регулярных выражениях. В качестве побочного эффекта от включения регулярных выражений нам нужно экранировать все специальные символы, в частности ., чтобы их можно было воспринимать буквально. В регулярном выражении нам нужно использовать \. для представления точки (в отличие от любого символа).

Первый шаг - выполнить эти замены с помощью sed, второй - передать каждую результирующую строку в качестве шаблона поиска на grep и выполнить поиск file1 для этого шаблона. Клей, который позволяет это сделать, - xargs, где {} - это заполнитель, представляющий одну строку из результатов команды sed.

Примечание:

Это не общее, безопасное решение, которое вы можете просто скопировать и вставить: вы должны следить за любыми символами в вашем файле, содержащими звездочки, которые считаются специальными в регулярных выражениях grep.


Обновление:

jhnc расширяет экранирование до любого из следующих символов: .\^$[], таким образом, учитывая почти все виды адресов электронной почты. Затем он / она избегает использования xargs, используя -f - для передачи результатов sed в качестве выражений поиска в grep:

sed 's/[.\\^$[]/\\&/g; s/[*]/./g' file2 | grep -f - file1

Это решение является более общим и более эффективным, см. Комментарий ниже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...