Class CSV
In: lib/csv.rb
Parent: Object

This program is copyrighted free software by NAKAMURA, Hiroshi. You can redistribute it and/or modify it under the same terms of Ruby‘s license; either the dual license version in 2003, or any later version.

Methods

Classes and Modules

Class CSV::BasicWriter
Class CSV::Cell
Class CSV::IOBuf
Class CSV::IOReader
Class CSV::IllegalFormatError
Class CSV::Reader
Class CSV::Row
Class CSV::StreamBuf
Class CSV::StringReader
Class CSV::Writer

Public Class methods

[Source]

    # File lib/csv.rb, line 93
93:   def CSV.foreach(path, rs = nil, &block)
94:     open_reader(path, 'r', ',', rs, &block)
95:   end

[Source]

     # File lib/csv.rb, line 110
110:   def CSV.generate(path, fs = nil, rs = nil, &block)
111:     open_writer(path, 'w', fs, rs, &block)
112:   end

Create a line from cells. each cell is stringified by to_s.

[Source]

     # File lib/csv.rb, line 160
160:   def CSV.generate_line(row, fs = nil, rs = nil)
161:     if row.size == 0
162:       return ''
163:     end
164:     fs ||= ','
165:     if fs.is_a?(Fixnum)
166:       fs = fs.chr
167:     end
168:     if !rs.nil? and rs.is_a?(Fixnum)
169:       rs = rs.chr
170:     end
171:     res_type = :DT_COLSEP
172:     result_str = ''
173:     idx = 0
174:     while true
175:       generate_body(row[idx], result_str, fs, rs)
176:       idx += 1
177:       if (idx == row.size)
178:         break
179:       end
180:       generate_separator(:DT_COLSEP, result_str, fs, rs)
181:     end
182:     result_str
183:   end

Convert a line from cells data to string. Consider using CSV.generate_line instead. To generate multi-row CSV string, see EXAMPLE below.

EXAMPLE

  row1 = ['a', 'b']
  row2 = ['c', 'd']
  row3 = ['e', 'f']
  src = [row1, row2, row3]
  buf = ''
  src.each do |row|
    parsed_cells = CSV.generate_row(row, 2, buf)
    puts "Created #{ parsed_cells } cells."
  end
  p buf

ARGS

  src: an Array of String to be converted to CSV string.  Must respond to
    'size' and '[](idx)'.  src[idx] must return String.
  cells: num of cells in a line.
  out_dev: buffer for generated CSV string.  Must respond to '<<(string)'.
  col_sep: Column separator.  ?, by default.  If you want to separate
    fields with semicolon, give ?; here.
  row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
    want to separate records with \r, give ?\r here.

RETURNS

  parsed_cells: num of converted cells.

[Source]

     # File lib/csv.rb, line 271
271:   def CSV.generate_row(src, cells, out_dev, fs = nil, rs = nil)
272:     fs ||= ','
273:     if fs.is_a?(Fixnum)
274:       fs = fs.chr
275:     end
276:     if !rs.nil? and rs.is_a?(Fixnum)
277:       rs = rs.chr
278:     end
279:     src_size = src.size
280:     if (src_size == 0)
281:       if cells == 0
282:         generate_separator(:DT_ROWSEP, out_dev, fs, rs)
283:       end
284:       return 0
285:     end
286:     res_type = :DT_COLSEP
287:     parsed_cells = 0
288:     generate_body(src[parsed_cells], out_dev, fs, rs)
289:     parsed_cells += 1
290:     while ((parsed_cells < cells) and (parsed_cells != src_size))
291:       generate_separator(:DT_COLSEP, out_dev, fs, rs)
292:       generate_body(src[parsed_cells], out_dev, fs, rs)
293:       parsed_cells += 1
294:     end
295:     if (parsed_cells == cells)
296:       generate_separator(:DT_ROWSEP, out_dev, fs, rs)
297:     else
298:       generate_separator(:DT_COLSEP, out_dev, fs, rs)
299:     end
300:     parsed_cells
301:   end

Open a CSV formatted file for reading or writing.

For reading.

EXAMPLE 1

  CSV.open('csvfile.csv', 'r') do |row|
    p row
  end

EXAMPLE 2

  reader = CSV.open('csvfile.csv', 'r')
  row1 = reader.shift
  row2 = reader.shift
  if row2.empty?
    p 'row2 not find.'
  end
  reader.close

ARGS

  filename: filename to parse.
  col_sep: Column separator.  ?, by default.  If you want to separate
    fields with semicolon, give ?; here.
  row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
    want to separate records with \r, give ?\r here.

RETURNS

  reader instance.  To get parse result, see CSV::Reader#each.

For writing.

EXAMPLE 1

  CSV.open('csvfile.csv', 'w') do |writer|
    writer << ['r1c1', 'r1c2']
    writer << ['r2c1', 'r2c2']
    writer << [nil, nil]
  end

EXAMPLE 2

  writer = CSV.open('csvfile.csv', 'w')
  writer << ['r1c1', 'r1c2'] << ['r2c1', 'r2c2'] << [nil, nil]
  writer.close

ARGS

  filename: filename to generate.
  col_sep: Column separator.  ?, by default.  If you want to separate
    fields with semicolon, give ?; here.
  row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
    want to separate records with \r, give ?\r here.

RETURNS

  writer instance.  See CSV::Writer#<< and CSV::Writer#add_row to know how
  to generate CSV string.

[Source]

    # File lib/csv.rb, line 83
83:   def CSV.open(path, mode, fs = nil, rs = nil, &block)
84:     if mode == 'r' or mode == 'rb'
85:       open_reader(path, mode, fs, rs, &block)
86:     elsif mode == 'w' or mode == 'wb'
87:       open_writer(path, mode, fs, rs, &block)
88:     else
89:       raise ArgumentError.new("'mode' must be 'r', 'rb', 'w', or 'wb'")
90:     end
91:   end

Parse lines from given string or stream. Return rows as an Array of Arrays.

[Source]

     # File lib/csv.rb, line 115
115:   def CSV.parse(str_or_readable, fs = nil, rs = nil, &block)
116:     if File.exist?(str_or_readable)
117:       STDERR.puts("CSV.parse(filename) is deprecated." +
118:         "  Use CSV.open(filename, 'r') instead.")
119:       return open_reader(str_or_readable, 'r', fs, rs, &block)
120:     end
121:     if block
122:       CSV::Reader.parse(str_or_readable, fs, rs) do |row|
123:         yield(row)
124:       end
125:       nil
126:     else
127:       CSV::Reader.create(str_or_readable, fs, rs).collect { |row| row }
128:     end
129:   end

Parse a line from given string. Bear in mind it parses ONE LINE. Rest of the string is ignored for example "a,b\r\nc,d" => [‘a’, ‘b’] and the second line ‘c,d’ is ignored.

If you don‘t know whether a target string to parse is exactly 1 line or not, use CSV.parse_row instead of this method.

[Source]

     # File lib/csv.rb, line 137
137:   def CSV.parse_line(src, fs = nil, rs = nil)
138:     fs ||= ','
139:     if fs.is_a?(Fixnum)
140:       fs = fs.chr
141:     end
142:     if !rs.nil? and rs.is_a?(Fixnum)
143:       rs = rs.chr
144:     end
145:     idx = 0
146:     res_type = :DT_COLSEP
147:     row = []
148:     begin
149:       while res_type == :DT_COLSEP
150:         res_type, idx, cell = parse_body(src, idx, fs, rs)
151:         row << cell
152:       end
153:     rescue IllegalFormatError
154:       return []
155:     end
156:     row
157:   end

Parse a line from string. Consider using CSV.parse_line instead. To parse lines in CSV string, see EXAMPLE below.

EXAMPLE

  src = "a,b\r\nc,d\r\ne,f"
  idx = 0
  begin
    parsed = []
    parsed_cells, idx = CSV.parse_row(src, idx, parsed)
    puts "Parsed #{ parsed_cells } cells."
    p parsed
  end while parsed_cells > 0

ARGS

  src: a CSV data to be parsed.  Must respond '[](idx)'.
    src[](idx) must return a char. (Not a string such as 'a', but 97).
    src[](idx_out_of_bounds) must return nil.  A String satisfies this
    requirement.
  idx: index of parsing location of 'src'.  0 origin.
  out_dev: buffer for parsed cells.  Must respond '<<(aString)'.
  col_sep: Column separator.  ?, by default.  If you want to separate
    fields with semicolon, give ?; here.
  row_sep: Row separator.  nil by default.  nil means "\r\n or \n".  If you
    want to separate records with \r, give ?\r here.

RETURNS

  parsed_cells: num of parsed cells.
  idx: index of next parsing location of 'src'.

[Source]

     # File lib/csv.rb, line 214
214:   def CSV.parse_row(src, idx, out_dev, fs = nil, rs = nil)
215:     fs ||= ','
216:     if fs.is_a?(Fixnum)
217:       fs = fs.chr
218:     end
219:     if !rs.nil? and rs.is_a?(Fixnum)
220:       rs = rs.chr
221:     end
222:     idx_backup = idx
223:     parsed_cells = 0
224:     res_type = :DT_COLSEP
225:     begin
226:       while res_type != :DT_ROWSEP
227:         res_type, idx, cell = parse_body(src, idx, fs, rs)
228:         if res_type == :DT_EOS
229:           if idx == idx_backup #((parsed_cells == 0) and cell.nil?)
230:             return 0, 0
231:           end
232:           res_type = :DT_ROWSEP
233:         end
234:         parsed_cells += 1
235:         out_dev << cell
236:       end
237:     rescue IllegalFormatError
238:       return 0, 0
239:     end
240:     return parsed_cells, idx
241:   end

[Source]

    # File lib/csv.rb, line 97
97:   def CSV.read(path, length = nil, offset = nil)
98:     CSV.parse(IO.read(path, length, offset))
99:   end

[Source]

     # File lib/csv.rb, line 101
101:   def CSV.readlines(path, rs = nil)
102:     reader = open_reader(path, 'r', ',', rs)
103:     begin
104:       reader.collect { |row| row }
105:     ensure
106:       reader.close
107:     end
108:   end

Private Class methods

[Source]

     # File lib/csv.rb, line 484
484:     def generate_body(cell, out_dev, fs, rs)
485:       if cell.nil?
486:         # empty
487:       else
488:         cell = cell.to_s
489:         row_data = cell.dup
490:         if (row_data.gsub!('"', '""') or
491:             row_data.index(fs) or
492:             (rs and row_data.index(rs)) or
493:             (/[\r\n]/ =~ row_data) or
494:             (cell.empty?))
495:           out_dev << '"' << row_data << '"'
496:         else
497:           out_dev << row_data
498:         end
499:       end
500:     end

[Source]

     # File lib/csv.rb, line 502
502:     def generate_separator(type, out_dev, fs, rs)
503:       case type
504:       when :DT_COLSEP
505:         out_dev << fs
506:       when :DT_ROWSEP
507:         out_dev << (rs || "\n")
508:       end
509:     end

[Source]

     # File lib/csv.rb, line 307
307:     def open_reader(path, mode, fs, rs, &block)
308:       file = File.open(path, mode)
309:       if block
310:         begin
311:           CSV::Reader.parse(file, fs, rs) do |row|
312:             yield(row)
313:           end
314:         ensure
315:           file.close
316:         end
317:         nil
318:       else
319:         reader = CSV::Reader.create(file, fs, rs)
320:         reader.close_on_terminate
321:         reader
322:       end
323:     end

[Source]

     # File lib/csv.rb, line 325
325:     def open_writer(path, mode, fs, rs, &block)
326:       file = File.open(path, mode)
327:       if block
328:         begin
329:           CSV::Writer.generate(file, fs, rs) do |writer|
330:             yield(writer)
331:           end
332:         ensure
333:           file.close
334:         end
335:         nil
336:       else
337:         writer = CSV::Writer.create(file, fs, rs) 
338:         writer.close_on_terminate
339:         writer
340:       end
341:     end

[Source]

     # File lib/csv.rb, line 343
343:     def parse_body(src, idx, fs, rs)
344:       fs_str = fs
345:       fs_size = fs_str.size
346:       rs_str = rs || "\n"
347:       rs_size = rs_str.size
348:       fs_idx = rs_idx = 0
349:       cell = Cell.new
350:       state = :ST_START
351:       quoted = cr = false
352:       c = nil
353:       last_idx = idx
354:       while c = src[idx]
355:         unless quoted
356:           fschar = (c == fs_str[fs_idx])
357:           rschar = (c == rs_str[rs_idx])
358:           # simple 1 char backtrack
359:           if !fschar and c == fs_str[0]
360:             fs_idx = 0
361:             fschar = true
362:             if state == :ST_START
363:               state = :ST_DATA
364:             elsif state == :ST_QUOTE
365:               raise IllegalFormatError
366:             end
367:           end
368:           if !rschar and c == rs_str[0]
369:             rs_idx = 0
370:             rschar = true
371:             if state == :ST_START
372:               state = :ST_DATA
373:             elsif state == :ST_QUOTE
374:               raise IllegalFormatError
375:             end
376:           end
377:         end
378:         if c == ?"
379:           fs_idx = rs_idx = 0
380:           if cr
381:             raise IllegalFormatError
382:           end
383:           cell << src[last_idx, (idx - last_idx)]
384:           last_idx = idx
385:           if state == :ST_DATA
386:             if quoted
387:               last_idx += 1
388:               quoted = false
389:               state = :ST_QUOTE
390:             else
391:               raise IllegalFormatError
392:             end
393:           elsif state == :ST_QUOTE
394:             cell << c.chr
395:             last_idx += 1
396:             quoted = true
397:             state = :ST_DATA
398:           else  # :ST_START
399:             quoted = true
400:             last_idx += 1
401:             state = :ST_DATA
402:           end
403:         elsif fschar or rschar
404:           if fschar
405:             fs_idx += 1
406:           end
407:           if rschar
408:             rs_idx += 1
409:           end
410:           sep = nil
411:           if fs_idx == fs_size
412:             if state == :ST_START and rs_idx > 0 and fs_idx < rs_idx
413:               state = :ST_DATA
414:             end
415:             cell << src[last_idx, (idx - last_idx - (fs_size - 1))]
416:             last_idx = idx
417:             fs_idx = rs_idx = 0
418:             if cr
419:               raise IllegalFormatError
420:             end
421:             sep = :DT_COLSEP
422:           elsif rs_idx == rs_size
423:             if state == :ST_START and fs_idx > 0 and rs_idx < fs_idx
424:               state = :ST_DATA
425:             end
426:             if !(rs.nil? and cr)
427:               cell << src[last_idx, (idx - last_idx - (rs_size - 1))]
428:               last_idx = idx
429:             end
430:             fs_idx = rs_idx = 0
431:             sep = :DT_ROWSEP
432:           end
433:           if sep
434:             if state == :ST_DATA
435:               return sep, idx + 1, cell;
436:             elsif state == :ST_QUOTE
437:               return sep, idx + 1, cell;
438:             else  # :ST_START
439:               return sep, idx + 1, nil
440:             end
441:           end
442:         elsif rs.nil? and c == ?\r
443:           # special \r treatment for backward compatibility
444:           fs_idx = rs_idx = 0
445:           if cr
446:             raise IllegalFormatError
447:           end
448:           cell << src[last_idx, (idx - last_idx)]
449:           last_idx = idx
450:           if quoted
451:             state = :ST_DATA
452:           else
453:             cr = true
454:           end
455:         else
456:           fs_idx = rs_idx = 0
457:           if state == :ST_DATA or state == :ST_START
458:             if cr
459:               raise IllegalFormatError
460:             end
461:             state = :ST_DATA
462:           else  # :ST_QUOTE
463:             raise IllegalFormatError
464:           end
465:         end
466:         idx += 1
467:       end
468:       if state == :ST_START
469:         if fs_idx > 0 or rs_idx > 0
470:           state = :ST_DATA
471:         else
472:           return :DT_EOS, idx, nil
473:         end
474:       elsif quoted
475:         raise IllegalFormatError
476:       elsif cr
477:         raise IllegalFormatError
478:       end
479:       cell << src[last_idx, (idx - last_idx)]
480:       last_idx = idx
481:       return :DT_EOS, idx, cell
482:     end

[Validate]