Поиск строк в текстовом файле, соответствующих регулярному выражению - PullRequest
20 голосов
/ 14 мая 2011

Может кто-нибудь объяснить, как я мог бы использовать регулярные выражения в Ruby только для того, чтобы возвращать совпадения строки.

Например, если код читается в файле .txt с серией имен в нем:

John Smith
James Jones
David Brown
Tom Davidson
etc etc

.. и слово для сопоставления вводится как 'ohn'затем он просто вернул бы «Джона Смита», но ни одно из других имен.

Ответы [ 4 ]

24 голосов
/ 14 мая 2011

Примечание: вместо File.each_line используйте IO.foreach в современных рубинах.Например:

[1] pry(main)> IO.foreach('./.bashrc') do |l|
[1] pry(main)*   puts l
[1] pry(main)* end
export PATH=~/bin:$PATH
export EDITOR='vi'
export VISUAL=$EDITOR

Происходит прогресс, и все меняется.


Вот несколько разных способов добраться туда, куда вы идете.

Заметьте, во-первых, я использую более идиоматический способ написания кода для чтения строк из файла.Библиотеки ввода-вывода и файлов в Ruby позволяют легко открывать, читать и закрывать файл в удобном и аккуратном пакете.

File.each_line('file.txt') do |li|
  puts li if (li['ohn'])
end

Он ищет слово «ohn» в любом месте строки, но не беспокоится орегулярное выражение.

File.each_line('file.txt') do |li|
  puts li if (li[/ohn/])
end

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

File.each_line('file.txt') do |li|
  puts li if (li[/ohn\b/])
end

Это немного более умный способ поиска имен, заканчивающихся на 'ohn'.Он использует регулярные выражения, но также указывает, что шаблон должен встречаться в конце слова.\b означает «границу слова».

Кроме того, при чтении файлов важно всегда думать заранее о том, может ли читаемый файл когда-либо превышать объем оперативной памяти, доступной вашему приложению.Легко прочитать весь файл в память за один проход, затем обработать его из ОЗУ, но вы можете нанести вред или убить ваше приложение или компьютер, если вы превысите доступную вам физическую память.


Знаете ли вы, если код, показанный другими ответами, на самом деле загружает весь файл в ОЗУ или каким-то образом оптимизирован путем потоковой передачи из функции readlines в функцию select?

Из IO # readlines документация:

Считывает весь файл, указанный именем, как отдельные строки и возвращает эти строки в массиве.Строки отделяются друг от друга:

Дополнительным соображением является выделение памяти во время большого объемного чтения.Даже если у вас достаточно ОЗУ, вы можете столкнуться с ситуациями, когда язык задыхается при чтении данных, обнаруживает, что ему не выделено достаточно памяти для переменной, и ему приходится делать паузу, когда он захватывает больше.Этот цикл повторяется до тех пор, пока не будет загружен весь файл.

Я стал чувствителен к этому много лет назад, когда загружал очень большой файл данных в приложение Perl на крупнейшем мини HP, которым я управлял.Приложение периодически останавливалось на пару секунд, и я не мог понять, почему.Я заглянул в отладчик и не смог найти проблему.Наконец, прослеживая пробежку с помощью операторов печати старой школы, я изолировал паузы в файле «slurp».У меня было много оперативной памяти и вычислительной мощности, но Perl не выделял достаточно памяти.Я перешел к чтению построчно, и приложение прошло обработку.Ruby, как и Perl, обладает хорошим вводом-выводом и может очень быстро читать большой файл, когда он читает построчно.Я никогда не находил веских причин для того, чтобы создавать текстовые файлы, за исключением случаев, когда возможно, чтобы содержимое, которое я хочу, было распределено по нескольким строкам, но это не обычное явление.

15 голосов
/ 14 мая 2011

Возможно, я не до конца понимаю проблему, но вы могли бы сделать что-то вроде:

File.readlines("path/to/file.txt").select { |line| line =~ /ohn/ }

, чтобы получить массив всех строк, соответствующих вашим критериям.

11 голосов
/ 14 мая 2011
query = 'ohn'
names = File.readlines('names.txt')
matches = names.select { |name| name[/#{query}/i] }
#=> ["John Smith"]

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

2 голосов
/ 17 мая 2017

Старый вопрос, но Array#grep также можно использовать для поиска в списке строк

File.readlines("names.txt").grep /#{query}/i
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...