正则表达式用于读取文件.txt并将信息返回到屏幕

时间:2009-11-22 06:51:31

标签: ruby

所以我想弄清楚在这种情况下如何从用户那里获取条目“CLOWN”和“112”。然后我获取这些值并将它们传递给File.foreach代码中的正则表达式。它打开了一个enrollment.txt文件。然后,代码应该获取.txt的所有行,并根据输入的两个值将其打印到屏幕

#WARNING RUBY NEWBIE MISTAKES PRESENT!
puts "Type search if you want to look for class information"

a = gets.to_s.chomp
while a != 'EXIT' do

if a == 'Search'

    puts 'Enter the 3 letter department you are looking for!(Example: CLOWN)'
    department = gets.to_s.chomp
    puts "You have entered #{department}"

    puts "Enter the 3 digit class number you are looking for!(Example: 112)"
    class_number = gets.to_i
    puts "You have entered #{class_number}"

end

File.foreach('enrollment.txt') do |line| puts line.scan~(/department/&&/classnumber/)
end  #PROBLEM IS HERE !!

puts "Would you like to quit? Type EXIT and hit enter!"
puts "or you can type Search and enter to look for another class!"
a = gets.to_s.chomp
end
puts "you have exited!"
File.close

我正在测试的字符串:

342 1936 CLOWN 110 ON HD CLOWN MAKE-CLASS 5.0 5.0 KRUSTY 798 MTWTh 7:30A 8:30A 24 13 11 4.3
342 1936 NINJA 117 ON HD NINJA CLASS 5.0 5.0 Jet-lee 798 MTWTh 8:30A 9:30A 24 13 11 4.3
342 1936 DEATHRACER 110 ON HD DEATHRACER DRIVING 5.0 5.0 FRANKENSTEIN 798 MTWTh 10:30A 11:30A 24 13 11 4.3

所以我试图基于.txt和我的两个得到的输出将是:

342 1936 CLOWN 110 ON HD CLOWN MAKE-CLASS 5.0 5.0 KRUSTY 798 MTWTh 7:30A 8:30A 24 13 11 4.3

我也知道正则表达式很好基于 http://rubular.com/

感谢您提供急需的帮助!

2 个答案:

答案 0 :(得分:1)

首先,在您列出的示例数据中,似乎没有任何行包含“CLOWN”和“112”。我将在本答案的其余部分假设您感兴趣的课程编号为“110”。

这一行似乎是你的问题:

line.scan~(/department/&&/classnumber/)

一个有用的调试工具是尝试将您的问题减少到一个小的测试用例。在Ruby和其他脚本语言中,在irb等交互式shell中使用该测试用例会很有帮助。让我们在irb中尝试使用一些模型数据,以便定义我们的变量:

>> department = "CLOWN"
=> "CLOWN"
>> classnumber = "110"
=> "110"
>> line = "342 1936 CLOWN 110 ON HD CLOWN MAKE-CLASS 5.0 5.0 KRUSTY 798 MTWTh 7:30A 8:30A 24 13 11 4.3"
=> "342 1936 CLOWN 110 ON HD CLOWN MAKE-CLASS 5.0 5.0 KRUSTY 798 MTWTh 7:30A 8:30A 24 13 11 4.3"
>> line.scan~(/department/&&/classnumber/)
TypeError: wrong argument type nil (expected Regexp)
 from (irb):4:in `scan'
 from (irb):4
 from :0
好的,所以有一些问题。第一个是scan~是无效的语法;方法只是scan

>> line.scan(/department/&&/classnumber/)
=> []

嗯。这次不是错误,但仍然没有结果。让我们看看它的组成部分是做什么的。我们在这一行中正在做的是计算/department/&&/classnumber/,然后将结果传递给scan字符串上的line方法。

>> /department/&&/classnumber/
=> /classnumber/

有趣。这只是给了我们传入的第二个正则表达式。为什么会这样?好吧,&&运算符有两个表达式。它计算第一个表达式。如果为false,则返回false。如果是,则计算第二个表达式。如果为false,则返回false。如果是,则返回第二个表达式。现在,除了falsenil之外,ruby中的每个值都被视为真实。因此,由于这两个正则表达式不是falsenil,因此它们都被视为true,而此表达式的结果是第二个组件/classnumber/

但即使假设第一个正则表达式被忽略,而且只使用了第二个正则表达式,为什么这不起作用呢?

>> line.scan(/classnumber/)
=> []

当您编写正则表达式/classnumber/时,您正在查找字符串中的文字字符classnumber。例如:

>> "string containing classnumber".scan(/classnumber/)
=> ["classnumber"]

然而,您想要寻找的是变量classnumber的值。有几种方法可以解决这个问题。您可以将该字符串传递给scan

>> line.scan(classnumber)
=> ["110"]

或者,您可以通过将classnumber变量插入其中来构建正则表达式:

>> line.scan(/#{classnumber}/)
=> ["110"]

现在,你有一些工作。但是你仍然希望与部门相匹配。你怎么能把两者结合起来?你可以将它们插入到同一个正则表达式中:

>> line.scan(/#{department} #{classnumber}/)
=> ["CLOWN 110"]

请注意,我在中间添加了一个空格,以匹配输入中部门和课程编号之间的空格。根据您的数据格式,您可能希望/#{department} +#{classnumber}/表示“一个或多个空格”,或/#{department}.*#{classnumber}/表示“任意数量的任何字符”;您必须拨打该电话自己。

哦,如果你想获得整行,你需要添加一些东西来匹配部门和班级编号之前和之后的文字:

>> line.scan(/.*#{department} #{classnumber}.*/)
=> ["342 1936 CLOWN 110 ON HD CLOWN MAKE-CLASS 5.0 5.0 KRUSTY 798 MTWTh 7:30A 8:30A 24 13 11 4.3"]

无论如何,我认为这是关于它的。您现在可以匹配已输入的部门和班级编号;如果你按照我用来解构你的问题的步骤,你可能会使用类似的技术来隔离和解决未来的问题。

答案 1 :(得分:0)

我不确定,但你可能想要

File.foreach('enrollment.txt') do |line| puts line.scan(/.*#{department} #{classnumber}:.*/)

编辑:您的代码中存在其他问题(class_number vs classnumber)并且它不是非常ruby-ish ...试试这个

#!/usr/bin/ruby -w
# vim: set fileencoding=utf-8 :

loop do
  puts "Type search if you want to look for class information, exit to exit"
  case gets.to_s.chomp
  when /search/i
    puts 'Enter the 3 letter department you are looking for!(Example: CLOWN)'
    department = gets.to_s.chomp
    puts "You have entered #{department}"

    puts "Enter the 3 digit class number you are looking for!(Example: 112)"
    class_number = gets.to_i
    puts "You have entered #{class_number}"

    File.new('enrollment.txt').readlines.each do |l|
      puts l if l =~ /#{department}/ &&  l =~ /#{class_number}/
    end
  when /exit/i
    puts "Exiting"
    break
  else 
    puts 'Command not understood'
  end
end