NAKAMURA, Hiroshi wrote: > Of cource I don't think everyone needs this "complexity" (and slowness). > Regexp based approach is very useful, too. (I often do that.) Added a bit of complexity in the form of error-checking. z ## Read, parse, and create csv records. z ## 2005-02-01, v. 2. z ## Added a pinch of optional error-checking. z z # The program conforms to the csv specification at this site: z # http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm z # The only extra is that you can change the field-separator. z # For a field-separator other than a comma, for example z # a semicolon: z # ";".is_fs z # z # After a record has been read and parsed, z # $csv_s contains the record in raw string format. z # z # If $csv_error_check == true, fields will be checked z # for improperly escaped double-quotes. z z class Array z def to_csv z ",".is_fs if $csv_fs.nil? z s = '' z self.map { |item| z str = item.to_s z # Quote the string if it contains the field-separator or z # a " or a newline, or if it has leading or z # trailing whitespace. z if str.index($csv_fs) or /^\s|"|\n|\s$/.match(str) z str = '"' + str.gsub( /"/, '""' ) + '"' z end z str z }.join($csv_fs) z end z def unescape z if $csv_error_check z self.map{ |x| z # Check for improperly escaped double-quotes. z raise "Bad field: #{x}" if x.gsub(/""/,'').index('"') z x.gsub( /""/, '"' ) } z else z self.map{|x| x.gsub( /""/, '"' ) } z end z end z end z z class String z # Set regexp for parse_csv. z # self is the field-separator, which must be z # a single character. z def is_fs z $csv_fs = self z if "^" == $csv_fs z fs = "\\^" z else z fs = $csv_fs z end z $csv_re = \ z ## Assumes embedded quotes are escaped as "". z %r{ \s* z (?: z "( [^"]* (?: "" [^"]* )* )" | z ( .*? ) z ) z \s* z [#{fs}] z }mx z end z z def parse_string z ",".is_fs if $csv_fs.nil? z (self + $csv_fs).scan( $csv_re ).flatten.compact.unescape z end z z end z z def get_rec( file ) z $csv_s = "" z begin z if file.eof? z raise "The csv file is malformed." if $csv_s.size>0 z return nil z end z $csv_s += file.gets z end until $csv_s.count( '"' ) % 2 == 0 z $csv_s.chomp! z $csv_s.parse_string z end z z $csv_error_check = true z z while rec = get_rec( ARGF ) z puts "----------------" z puts $csv_s z p rec z puts rec.to_csv z end