Майнинг простого текста

Майнинг простого текста

(оригинальное название: grep в терминах абзацев, а не строк)

Этот вопрос вызван тем fzf, что позволяет мне найти определенный файл в моей огромной файловой системе.нечетко и постепенно, обеспечивая очень-очень быстрый поиск (см. множество симпатичных гифок в этомстатья).

Я имею в виду делать то же самое со своими заметками. У меня есть куча мимолетных заметок, дневников, меморандумов и т. д. в текстовом формате. Длячитабельность, каждая строка содержит не более 72 символов. Это затрудняет поиск по моей заметке, исходя из моих наивных знаний о существующих инструментах поиска, таких как grep, ripgrep..

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

1  Victim mentality is an acquired personality trait in which a person
2  tends to recognize or consider themselves as a victim of the negative
3  actions of others, and to behave as if this were the case in the face
4  of contrary evidence of such circumstances. Victim mentality depends
5  on clear thought processes and attribution.
6
7  (from wikipedia: Victim mentality)

Допустим, я взял эту записку полгода назад и знал, что она где-то в моей файловой системе. Как обычно, мы не можем процитировать точные слова, номы помним контекст! grepтексты типа personality, clear thought, или victimчерез мою файловую систему, скорее всего, дадут мнеслишкоммного важных для меня вещей, которые нужно действительно сузить.

Должен быть инструмент (существующий или нет), помогающий искать такие тексты.Наши старые заметки (в текстовом виде) будут гораздо более ценными. Есть ли способ сделать это с нашим старым добрым другом grepи его родственниками? Или есть другие способы, которые сработают? Любое мнение также будет высоко оценено.

решение1

Давайте разобьем процесс (поиска) на более мелкие части.

Сначала нам нужно получить список файлов, в которых вы хотите выполнить поиск, например, в текущем каталоге ( .) все файлы с расширением txt ( -name "*.txt"), которые, безусловно, являются файлами ( -type f):

find . -name "*.txt" -type f

Этот результат можно использовать в качестве входных данных для grepпоиска somethingвнутри этих файлов, включая номер строки и имя файла в вывод, игнорируя регистр ( -nHi), +в конечном итоге это гарантирует, что все файлы будут просмотрены за одно выполнение (а не по одному за раз):

find . -name "*.txt" -type f -exec grep -nHi 'something' {} +

Если количество файлов слишком велико (> $ARG_MAX), вам следует заменить+с \;.

Вывод предыдущей команды выглядит примерно так:

./some/dir/somewhere/songs.txt:128:But had me believing it was always something that I'd done
./some/dir/somewhere/songs.txt:883:Was never something I pursued
./some/dir/somewhere/songs.txt:2905:I know something about love 
./some/dir/somewhere/songs_other.txt:11780:will come across something like this:  F (Dshape).

Таким образом, если разделить эти строки, то :получится 3 компонента: имя файла, номер строки, в которой было найдено совпадение, и сама строка.

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

Для вашего примера текста, если вы ищете ваши 3 термина ( personality, clear thought, victim), вы получили соответствующие номера строк 1, 5 и 2, поэтому расстояние для этого файла (начиная с первого термина)

abs(1-5) + abs(1-2) = 5 

Таким образом, вы можете сортировать файлы в зависимости от того, содержат ли они все термины и находятся ли они ближе всего к данному файлу.

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

решение2

Простая однострочная команда Perl может выполнить эту работу. Следующий код выведет имя файла, за которым последует «found», если все ключевые слова (т. е. personalityи clear thoughtи victimприсутствуют в файле).

perl -0777 -ane 'print "$ARGV: found\n" if /^(?=.*personality)(?=.*clear thought)(?=.*victim)/s' file.txt 

Выход:

file.txt: found

Объяснение:

-0777       # slurp mode
-ane        # read the file ans execute the following
print "$ARGV: found\n"      # print,$ARGV contains the current filename
if                          # if
  /                         # regex delimiter
    ^                       # begining of file
      (?=.*personality)     # positive lookahead, make sure we have "personality"
      (?=.*clear thought)   # positive lookahead, make sure we have "clear thought"
      (?=.*victim)          # positive lookahead, make sure we have "victim"
  /s                        # regex delimiter, s = dot matches newline

Если вы хотите искать во всех txt-файлах, используйтеperl ...... *.txt

Связанный контент