LINUX.ORG.RU

Поиск в массивах по подстрокам, ruby

 


0

1

Здравствуйте. Имеется текстовый файл с тысячей с лишним строчек вида (улица<пробел>дом-подъезд<табуляция>ip-адрес узла<переход на новую строку>)

Садовая 119-1 xxx.xxx.yyy.yyy
Ленина 113-2 xxx.xxx.yyy.yyy
Ленина 113-6 xxx.xxx.yyy.yyy

Нужно сделать поиск по файлу: я ввожу улицу и номер дома(без подъезда, т.к. узлы сети стоят не в каждом из них), а мне должна вернуться строка целиком (или несколько, по количеству совпадений). Дальше должно быть запоминание соответствующих ip-адресов в переменные и подстановка их в уже написанный скрипт, но это отдельный вопрос. Сейчас имею такое начало:

#!/usr/bin/ruby
# encoding: utf-8
puts "Что ищем?"
find=gets.chomp
buffer=[]
File.open("/home/hasculdr/Документы/bin/allKom").each { |line|
buffer<<line.split("\n")}
#puts buffer
if buffer.include?(find) then puts "Да"
else puts "Нет"
end
«puts buffer» выводит мне весь текстовый файл (т.е. массив таки создается), но если я начинаю искать внутри переменной по подстрокам - то мне ничего не возвращается - для проверки добавил условие, всегда возвращает «Нет»:
if buffer.include?(find) then puts "Да"
else puts "Нет"
end
Как лучше решить эту задачу - через массив или хеш? Можно ли введенную пользователем часть адреса дома преобразовать в регулярное выражение и выполнять поиск по нему, или регулярки здесь не нужны? Если делать через хеш, то нужно ли редактировать файл с данными до вида

«Садовая 119-1» => «xxx.xxx.yyy.yyy»
«Ленина 113-2» => «xxx.xxx.yyy.yyy»
«Ленина 113-6» => «xxx.xxx.yyy.yyy»

?

Ответ на: комментарий от anonymous

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

hasculdr ()

не знаю раби

#!/usr/bin/python
# encoding: utf-8

import os

print "Что ищем?"
find = raw_input()
ips = []
for line in open('/home/hasculdr/Документы/bin/allKom'):
    if find.lower() in line.lower():
        print line.strip()
        ips.append(line.split()[-1])

print "Применить скрипт (y/n)?"
if raw_input() == 'y':
    for ip in ips:
        os.system('/path/to/script --ip="%s"' % ip)
pawnhearts ★★★★★ ()

А вообще зачем тебе тут ruby? Используй просто grep

grep Ленина /home/hasculdr/Документы/bin/allKom | awk '{print $3}' |xargs -n1 ./yourscript

pawnhearts ★★★★★ ()
Ответ на: комментарий от pawnhearts

Нафиг тут sql там всего 1000 строк.

Нафиг тут ruby там всего 1000 строк, ищите глазами.

anonymous ()
Ответ на: комментарий от pawnhearts

grep Ленина /home/hasculdr/Документы/bin/allKom | awk '{print $3}' |xargs -n1 ./yourscript

Писатель, блин!

awk '/Ленина/ {system(«/path/to/yourscript $3»)}' /home/hasculdr/Документы/bin/allKom

anonymous ()
Ответ на: комментарий от pawnhearts

grep Ленина /home/hasculdr/Документы/bin/allKom | awk '{print $3}' |xargs -n1 ./yourscript

Как эта команда подставит ip-адрес в переменную telnet внутри скрипта? Скрипт интерактивный (несколько вариантов настроек),тоже написан на ruby и выполняет большую последовательность команд через телнет. У вас легкий и интересный способ решения задачи, но я бы «для собственного развития» хотел все сделать именно в ruby(.

hasculdr ()
Ответ на: комментарий от pawnhearts

$host=Net::Telnet::new(«Host» => $ip, «Timeout» => 10, «Waittime» => 1, «Prompt» => /[#>\]-]/) вот так в ruby создается переменная для работы с telnet. Решил пока копать в сторону хешей.

hasculdr ()
Ответ на: комментарий от hasculdr

Решил пока копать в сторону хешей.

Хочешь сделать правильно — используй sql. И дело не в объёмах данных, а в унификации поискового механизма, добавления, изменения, удаления данных. Захочется сделать программку для андроида, там есть sqlite3, захочешь web приложение, там тоже sql используется в полных рост. Хочешь дрочить в присядку делай regexp'ы, hash'ы и пр. наколеночное поделие.

anonymous ()
Ответ на: комментарий от anonymous

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

hasculdr ()

Вот, может оно будет работать:

cho_ishem = gets.chomp
buffer = IO.readlines("/home/hasculdr/Документы/bin/allKom")
buffer.each do |ln|
  puts ln if /#{cho_ishem}(.*)\s/ == ln
end

Deleted ()
Ответ на: комментарий от Deleted

Спасибо, можно комментарий по вашему блоку? { |ln| puts ln if /#{cho_ishem}(.*)\s/ === ln} - выводится на экран каждый элемент массива из внешнего файла, соответствующий условию. /#{cho_ishem}(.*)\s/ - это регулярное выражение с переменной внутри? Ввод должен совпадать с началом элемента массива, звездочка в скобках задает любые остальные символы после введенного шаблона?

hasculdr ()
Ответ на: комментарий от hasculdr

Сделал так:

#!/usr/bin/ruby
# encoding: utf-8
find="Ленина"
buffer=[]
File.open("/home/hasculdr/Документы/bin/allKom_tab").each { |line|
buffer=line.split("\t")} # делим файлик с коммутаторами по символу ТАБУЛЯЦИИ (между номером дома и ip-адресом)
result=Hash[*buffer.flatten] # полученный двумерный массив плющим методом flatten, а затем пихаем его в хеш result
puts result.key?(/#{find}*/)
Проверил отдельно ключи, писал полностью улицу, дом и подъезд - находит. Строковую переменную, засунутую в регулярку - нет. Версия ruby 1.9.3 (новее на мой дистр пока нет).

hasculdr ()
Ответ на: комментарий от hasculdr

это регулярное выражение с переменной внутри?

Да

Ввод должен совпадать с началом элемента массива, звездочка в скобках задает любые остальные символы после введенного шаблона?

Почти, совпадения будут искаться c ln только до последнего пробела, то-есть часть строки с айпишником парситься не будет

Deleted ()
Ответ на: комментарий от hasculdr

Make every program a filter.

#!/usr/bin/env ruby
# name: search

file = STDIN.gets.strip

street, house_number = ARGV
house_number ||= '(?:\d+)'
entrance = '(?:-\d+)?'
ip = '(.*)'

puts IO.readlines(file)
  .grep(/^#{street}\s#{house_number}#{entrance}\s+#{ip}$/){$1}
  .join($/)

Использовать как фильтр:

echo /path/to/file | ./search Ленина 113 | less

Версия ruby 1.9.3 (новее на мой дистр пока нет).

Это очень плохо. 1.9.3 больше не поддерживается.

Рекомендую воспользоваться ruby-build и chruby.

Anatolik ★★ ()
Ответ на: комментарий от Deleted

Нашел на stackoverflow измененный класс Hash, теперь удается корректно искать по регулярным выражениям. Но .key? возвращает только true/false значения. Как мне при поиске по части ключа получить пару ключ-значение целиком?

upd. Похоже, мне проще искать «подмассив(ы)» в двумерном массиве и дальше работать с ними.

hasculdr ()

нужно ли редактировать файл с данными до вида

«Садовая 119-1» => «xxx.xxx.yyy.yyy» «Ленина 113-2» => «xxx.xxx.yyy.yyy» «Ленина 113-6» => «xxx.xxx.yyy.yyy»

Нужно до вида

---
"Садовая 119-1": xxx.xxx.yyy.yyy
"Ленина 113-2": xxx.xxx.yyy.yyy
"Ленина 113-6": xxx.xxx.yyy.yyy
require 'yaml'
p YAML.load_file '/path/to/file.yml' #{"Садовая 119-1"=>"xxx.xxx.yyy.yyy", "Ленина 113-2"=>"xxx.xxx.yyy.yyy", "Ленина 113-6"=>"xxx.xxx.yyy.yyy"}

Вот так легко и непринужденно получаем хэш их текстового (yaml) файла.

special-k ★★★ ()
Последнее исправление: special-k (всего исправлений: 2)
Ответ на: комментарий от hasculdr

Как мне при поиске по части ключа получить пару ключ-значение целиком?

{"Садовая 119-1" => "xxx.xxx.yyy.yyy", "Ленина 113-2" => "xxx.xxx.yyy.yyy", "Ленина 113-6" => "xxx.xxx.yyy.yyy", "Хуенина 13-6" => "xxx.xxx.yyy.yyy"}.select{|k, v|
  k.match /ху/i
} #{"Хуенина 13-6"=>"xxx.xxx.yyy.yyy"}
special-k ★★★ ()
require 'yaml'
YAML.load_file('/path/to/file.yml').select{|k, v| k ~= /ху/i}.each{|k, v|
  #ваши самые откровенные желания
}

Однострочник, ёпта. Питонщеги сосите.

special-k ★★★ ()
Последнее исправление: special-k (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.