The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Text::xSV - read character separated files

SYNOPSIS

  use Text::xSV;
  my $csv = new Text::xSV;
  $csv->open_file("foo.csv");
  $csv->bind_header();
  while ($csv->get_row()) {
    my ($name, $age) = $csv->extract(qw(name age));
    print "$name is $age years old\n";
  }

DESCRIPTION

This module is for reading character separated data. The most common example is comma-separated. However that is far from the only possibility, the same basic format is exported by Microsoft products using tabs, colons, or other characters.

The format is a series of rows separated by returns. Within each row you have a series of fields separated by your character separator. Fields may either be unquoted, in which case they do not contain a double-quote, separator, or return, or they are quoted, in which case they may contain anything, and will encode double-quotes by pairing them. In Microsoft products, quoted fields are strings and unquoted fields can be interpreted as being of various datatypes based on a set of heuristics. By and large this fact is irrelevant in Perl because Perl is largely untyped. The one exception that this module handles that empty unquoted fields are treated as nulls which are represented in Perl as undefined values. If you want a zero-length string, quote it.

People usually naively solve this with split. A next step up is to read a line and parse it. Unfortunately this choice of interface (which is made by Text::CSV on CPAN) makes it impossible to handle returns embedded in a field. Therefore you may need access to the whole file.

This module solves the problem by creating a CSV object with access to the filehandle, if in parsing it notices that a new line is needed, it can read at will.

USAGE

First you set up and initialize an object, then you read the CSV file through it. The creation can also do multiple initializations as well. Here are the available methods

new

This is the constructor. It takes a hash of optional arguments. They are the filename of the CSV file you are reading, the fh through which you read, an optional filter and the one character sep that you are using. If the filename is passed and the fh is not, then it will open a filehandle on that file and sets the fh accordingly. The separator defaults to a comma. If the filter is present the lines will be passed through it as they are read. This is useful for stripping off \r, and for stripping out things like Microsoft smart quotes at the source.

set_filename
set_fh
set_filter
set_sep

Set methods corresponding to the optional arguments to new.

open_file

Takes the name of a file, opens it, then sets the filename and fh.

bind_fields

Takes an array of fieldnames, memorizes the field positions for later use. bind_headers is preferred.

bind_headers

Reads a row from the file as a header line and memorizes the positions of the fields for later use. File formats that carry field information tend to be far more robust than ones which do not, so this is the preferred function.

get_row

Reads a row from the file. Returns an array or reference to an array depending on context. Will also store the row in the row property for later access.

extract

Extracts a list of fields out of the last row read.

BUGS

When I say single character separator, I mean it.

Performance could be better. That is largely because the API was chosen for simplicity of a "proof of concept", rather than for performance. One idea to speed it up you would be to provide an API where you bind the requested fields once and then fetch many times rather than binding the request for every row.

Also note that should you ever play around with the special variables $`, $&, or $', you will find that it can get much, much slower. The cause of this problem is that Perl only calculates those if it has ever seen one of those. This does many, many matches and calculating those is slow.

I need to find out what conversions are done by Microsoft products that Perl won't do on the fly upon trying to use the values.

I need a real test suite.

AUTHOR AND COPYRIGHT

Ben Tilly (ben_tilly@operamail.com). Originally posted at http://www.perlmonks.org/node_id=65094.

Copyright 2001. This may be modified and distributed on the same terms as Perl.