Как искать строку в очень большом файле с очень длинными строками?

Хорошо, вот ответ на мое конкретное требование. Как отмечалось выше в комментариях, в строке Hostможно указать более одного имени :

.
Host cheddar.halon.org.uk cheddar halon
    Hostname cheddar.halon.org.uk

Очень просто!

3
16.11.2021, 09:32
2 ответа

Это было бы медленным, так как он считывал бы входной файл несколько раз (один раз для каждого символа в строке, которую вы хотите найти, каждый раз в строках размером этой строки поиска ), но это должно работать с файлами любого size со строками любого размера, используя GNU awk для mult -char RSиRT(untested):

awk -v str='search-string-here' '
    BEGIN {
        lgth = length(str)
        RS = sprintf("%*s",lgth,"")
        gsub(/ /,".",RS)
        for (i=1; i<lgth; i++) {
            ARGV[ARGC++] = ARGV[1]
        }
    }
    RT == str {
        print "found"
        exit
    }
' file

Он устанавливает RS в N .с, где N — длина вашей строки поиска, считывая каждую цепочку из N символов из ввода, начиная с char #1, сравнивая их со строкой поиска и выходя, если текущая N символов из ввода соответствует строке поиска. Если на этом проходе нет совпадений, он делает то же самое снова, но начиная с char #2, и так далее, пока это не будет сделано N раз, и поэтому во входном файле больше нет строк длины N для сравнения со строкой поиска..

Обратите внимание, что в приведенном выше примере выполняется сравнение строк, а не регулярное выражение. Чтобы выполнить сравнение регулярных выражений, вам нужно определить максимальную длину совпадающей строки другим способом, а затем использовать оператор сравнения регулярных выражений ~вместо ==, например. если вы знаете, что совпадающая строка во входных данных не может быть длиннее 20 символов, вы можете сделать что-то вроде:

awk -v regexp='search-regexp-here' '
    BEGIN {
        lgth = 20
        RS = sprintf("%*s",lgth,"")
        gsub(/ /,".",RS)
        for (i=1; i<lgth; i++) {
            ARGV[ARGC++] = ARGV[1]
        }
    }
    RT ~ regexp {
        print "found"
        exit
    }
' file

но этот поиск по регулярному выражению имеет некоторые недостатки, которых нет у строкового поиска, о которых вам придется подумать, например. если ваше регулярное выражение поиска включает ^или $для границ, вы можете получить ложное совпадение выше, поскольку оно создает границы начала/конца строки вокруг каждого символа, когда читаются длинные строки N -символов -.

1
16.11.2021, 17:45

Вот простое частичное решение, которое работает, только если есть символ, который не появляется в строке (или регулярном выражении )для поиска, но появляется достаточно часто в строке , так что интервал между вхождениями этого символа всегда умещается в памяти. Например, предположим, что каждая строка представляет собой очень длинный список относительно коротких полей, разделенных точкой с запятой -.

<large-file-with-long-lines.txt tr ';' '\n' | grep 'search-string-here'

Вот другое частичное решение, которое работает, если вхождения всегда начинаются с кратного N символов после начала строки для некоторого фиксированного N. Он используетfoldдля переноса строк иagдля многострочного поиска. Известно, что в этом примере вхождения всегда начинаются через 3 *x символов после начала строки.

<large-file-with-long-lines.txt fold -w3 | ag $'cat\ntag\ngag\nact'

Это может быть обобщено для поиска произвольных строк путем повторения поиска для каждого смещения.

<large-file-with-long-lines.txt fold -w3 | ag $'fee\n-fi\n-fo\n-fu\nm|fe\ne-f\ni-f\no-f\num|f\nee-\nfi-\nfo-\nfum'

Обратите внимание, что это может иметь ложные срабатывания, если строка почти присутствует, но с разрывом строки посередине.

3
16.11.2021, 11:15

Теги

Похожие вопросы