开发者

Why / How is my variable getting set to nil

I have some code that reads a file into an array of lines, and then parses those lines to get at the structured data. The input file has various different data types that need to be handled differently, additionally there are major sections for various accounts (mobile numbers).

I loop through the lines looking for the account line, identify the account, and then I want to use that account until I encounter the next account line. The lines in between potentially represent various types of data belonging to that account. The problem is, after I find the account line and set a local variable (cur_num), the variable is set to nil when I want to use it. Why, how is this happening? I am learning Ruby so I want more than a fix - I want to understand why it works this way.

Here is my code:

  count = 0
  cur_num = ""
  lines.each do |line|
  unless (line.strip.eql?(""))  # edited due to comment from normalocity
    if (line.slice(0,15) == "Mobile Number:,")
      cur_num = line.slice(15,12)
      count = 1
      puts "Current Number: #{cur_num}"
      #puts "Object Type: #{cur_num.class}"
    else 
      data = line.strip.split(',')
      if (data.length > 8)
        data.unshift(cur_num)
        #if (count.modulo(10) == 0 || count == 1)
          puts "[#{cur_num}] #{data.inspect}"
          #pp data
        #end
        count += 1
      end
    end
  end
end

A开发者_StackOverflow社区n overview of the input data structure would look like this:

Account 1
    Data Section A
        data line 1
        data line 2
     Data Section B
        data line 1
        data line 2
Account 2
    Data Section A
        data line 1
        data line 2
     Data Section B
        data line 1
        data line 2

end

adding code to duplicate lines array you should paste this above code sample if you are attempting to duplicate. I'm putting it here at the end to try to make my question more readable:

lines = []
lines.push("ATT Wireless Bill")
lines.push("")
lines.push("Mobile Number:,770-555-1212")
lines.push("item,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge")
lines.push("")
lines.push("1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00")
lines.push("")
lines.push("2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00")
lines.push("")
lines.push("1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00")
lines.push("")
lines.push("Mobile Number:,770-555-1213")
lines.push("item,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge")
lines.push("")
lines.push("1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00")
lines.push("")
lines.push("2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00")
lines.push("")
lines.push("1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00")
lines.push("")


Answer to the answer Why / How is my variable getting set to nil

Without cur_num = "" you don't initialize cur_num outside the loop (lines.each). So cur_num is initialized in each loop.

I would expect a undefined local variable or method error, but it seems cur_num is created in each loop, even, if the if-branch is not executed. So you have cur_num, but without a value (or better: it is nil).

I added a short example to show, that a variable is created, even if the code is not executed:

if false
  a = 1
else
  p a #works fine, a was created, but it is nil
  p b #undefined local variable or method `b' 
end

Addendum II:

The following code shows, that a variable inside a loop is 'loop internal'. The 2nd (and following) cycle(s) starts without the variable a.

#~ a = 0  # uncomment to compare
5.times{
  if defined? a
    puts "a is defined as #{a.inspect}"
  else
    puts "a is not defined"
    a = 1 #define it now
  end
}

Related questions: The scope is confusing


I redesigned your code a bit. When I parse texts like yours, I prefer to use a case-statement with regular expressions:

count = 0
cur_num = ""
DATA.each_line do |line|
  case line
    when /\A\s\Z*/ #skip empty lines
    when /Mobile Number:,(.{12})/
      cur_num = $1
      count = 1
      puts "Current Number: #{cur_num}"
      #puts "Object Type: #{cur_num.class}"
    else 
      data = line.strip.split(',')
      if data.length > 8
        data.unshift(cur_num)
        #if (count.modulo(10) == 0 || count == 1)
          puts "[#{cur_num}] #{data.inspect}"
          #pp data
        #end
        count += 1
      end #(data.length > 8)
  end #case line
end

__END__
ATT Wireless Bill

Mobile Number:,770-555-1212
item,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge

1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00

2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00

1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00

Mobile Number:,770-555-1213
item,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge

1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00

2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00

1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00


After staring at this for over an hour, comparing two nearly identical versions, one that worked, one that didn't, I am able to make it fail or succeed by commenting out a single line. here is the exact code I am running: [Edit note, altered the code to prevent vertical scroll bar in code sample]

#!/usr/local/bin/ruby
my_input ="ATT Wireless Bill\n\nMobile Number:,770-555-1212\n\nitem,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge\n\n1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00\n\n"
my_input << "2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00\n\n1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00\n\nMobile Number:,770-555-1213\n\nitem,date,time,number called,rate period,plan type,minutes,airtime charge,ld charge,total charge\n\n"
my_input << "1,2011-01-02,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00\n\n2,2011-01-03,6:56AM,404-555-1212,NW,UNW,4,0.00,0.00,0.00\n\n1,2011-01-03,7:56AM,404-555-1213,DT,UM2M,5,0.00,0.00,0.00\n\n"
lines = my_input.split("\n")
count = 0
cur_num = "" # Line  7 - Comment out this line to see failure
lines.each do |line|
unless (line.strip.eql?(""))
  if (line.slice(0,15) == "Mobile Number:,")
    cur_num = line.slice(15,12)
    count = 1
    puts "Current Number: #{cur_num}"
    #puts "Object Type: #{cur_num.class}"
  else 
    data = line.strip.split(',')
    if (data.length > 8)
      data.unshift(cur_num)
      #if (count.modulo(10) == 0 || count == 1)
        puts "[#{cur_num}] #{data.inspect}"
        #pp data
      #end
      count += 1
    end
    end
  end
end

If I comment out line 7, then cur_val is nil on lines 18 and 20.

Can someone please explain why?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜