Распечатать различия между несортированными строками из файлов - PullRequest
1 голос
/ 17 апреля 2019

У меня есть два файла, которые содержат n строк со строкой в ​​каждой строке.Я хочу распечатать разницу в символах между этими списками.Вы можете представить операцию как своего рода «вычитание» букв.Вот как это должно выглядеть:

List1       List2      Result
AaBbCcDd    AaCcDd     Bb
AaBbCcE     AaBbCc     E
AaBbCcF     AaCcF      Bb

Это означает, что второй список отсортирован не по алфавиту, а все удаляемые подстроки отсортированы внутри каждой строки (Aa предшествует Bb раньшеCc).Обратите внимание, что удаляемые элементы могут иметь длину 1 или 2 символа (Aa или F), всегда начинающиеся с заглавных букв, за которыми (иногда) следует строчная буква.Строки полностью состоят из перестановок нескольких «элементов», таких как Aa, Bb, Cc, Dd, E, F, Gg, ... и т. Д.

Этот вопрос был дан в очень похожей форме: Сценарий Bash Найти разницу между двумя строками , но только для двух строк, введенных вручную, тогда как мне нужно выполнять операцию много сотен раз.Я пытаюсь реализовать файлы в качестве источника этой команды, а также правильно разделять символы.Вот моя адаптация:

split_chars() { sed $'s/./&\\\n/g' <<< "$1"; }
comm -23 <(split_chars AaBbCcDd) <(split_chars AaCcDd)

, которая дает в качестве вывода

B
b

, так что все еще не совсем то, что я хочу, даже в этом единственном случае.Я предполагаю, что команда split_chars является ключевой здесь, но я не смог применить ее к моим файлам в любом случае.Помещение имен файлов в скобки не работает, очевидно.Для справки, простой

commm -23 List1 List2

просто приводит к

AaBbCcDd
AaBbCcEe
AaBbCcF
comm: file 2 is not in sorted order

Ответы [ 2 ]

1 голос
/ 17 апреля 2019

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

split() { sed 's/[A-Z]/\n&/g' <<< "$1"; }

Разделение строки можно отменить, удалив все символы новой строкииспользование tr -d \\n.

Чтобы вычесть список строк из другого списка строк, вы можете использовать grep без необходимости сортировки.

grep -vFxf subtrahend minuend

Это будет печатать в исходном порядке эти строкииз файла minuend, которого нет в файле subtrahend.

Чтобы собрать все воедино, вам нужно

  • читать оба файла построчно
  • разбить каждую строку на список строк
  • вычесть эти списки
  • отменить разбиение

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

split() { sed 's/[A-Z]/\n&/g' <<< "$1"; }
subtract() { grep -vFxf "$2" "$1"; }
union() { tr -d \\n; echo; }
paste List1 List2 | while read -r minuend subtrahend; do
    subtract <(split "$minuend") <(split "$subtrahend") | union
done

Bash-скрипты с циклами работают медленно.Если вам нужно более быстрое решение, вы должны переписать этот скрипт на более продвинутом языке, таком как perl или python.

0 голосов
/ 17 апреля 2019

Другой в GNU awk:

$ gawk 'NR==FNR {
    a[FNR]=$0
    next
}
{
    patsplit($0 a[FNR],b,/[A-Z][a-z]?/)
    printf "%s%s%s", a[FNR],OFS,$0
    for(i in b)
        if(!(match($0,b[i])&&match(a[FNR],b[i])))
            printf "%s%s", OFS, b[i]
    print ""
}' file1 file2

Вывод:

List1 List2
AaBbCcDd AaCcDd Bb
AaBbCcE AaBbCc E
AaBbCcF AaCcF Bb
...