# Jeff Walters, hiker_jjw@yahoo.com Everyone who works with CGI/Perl and the Internet knows that database interaction is essential, from Web Store programs to a database of friendly quotes. The problem I have always had is not the complexity of the database, but finding a simple and cost effective way to let a Website owner manage his/her own database; usually from a MS Windows system. The most simple database is the '|' pipe delimited database, but owners soon find out that editing a large database in a text editor becomes a rather tedious task. Copying and pasting text is the only way to speed up the process of building the database, but it is often too easy to get columns of data mixed up. At the other end is the SQL database and MS Access. Some owners find SQL databases overwhelming and find MS Access too restrictive, hard to use and expensive. My solution is to use the .CSV file format - Comma Separated Values. Most spreadsheet programs such as MS Excel will enable you to save files in the .CSV format. Most Website owners already have MS Excel on their computers and are also very comfortable using it. Copying and pasting fields is a very easy process and keeping columns aligned is no longer a problem. Despite the name .CSV, the .CSV file format does allow you to use both commas and quotes in your database fields. I've noticed from MS Excel that there are two rules that MS Excel follows when it exports a spreadsheet to the .CSV format. First, if the cell contains a double quote (") then change all double quotes (") to two double quotes (""). Second, if the cell contains a comma or a double quote, then surround the data with double quotes ("___data___"). These two rules define the logic needed to split the .CSV file data line. The logic in the SplitData subroutine below isn't exactly pretty, but it will handle just about every case I could come up with. To summarize it, the subroutine splits the CSV file data line by commas using the split() function. Since some of the fields may have contained commas, we then proceed to recombine the data based on the logic of the above two rules. The data fields are then returned in the array @output. There is one small limitation to using MS Excel that could be annoying (hey, it's a MS product remember?). It seems that a text cell is limited to a maximum character length of 255. In most cases this is not a problem. On the other hand, Web Store database descriptions might exceed 255 characters, especially if you include HTML in the cell. The solution to this is to just add a description2 field to your database. If anyone is interested in the code changes required to implement this subroutine into the Web Store program (web_store.cgi) just follow these simple changes. 1.) Open web_store_db_lib.pl 2.) Copy and Add the SplitData subroutine shown below to the web_store_db_lib.pl file just before 1; 3.) Find subroutine: check_db_with_product_id Replace (or comment out #): @db_row = split(/\|/,$line); with @db_row = &SplitData($line); 4.) Find subroutine: submit_query Replace (or comment out #): @db_row = split(/\|/,$line); with @db_row = &SplitData($line); 5.) Save and Updata via FTP. A working version of the subroutine with the Web Store program can be found at www.outdoorstoreusa.com ############################################################ # # subroutine: SplitData # # Usage: # @output = &SplitData($data_line); # # Input: # $data_line = the CSV file line to be separated. # # Function: # This subroutine is used to split a (.CSV) comma separated # values database line ($data_line). This subroutine was # written to be used with a .CSV file exported from MS Excel # or another Spreadsheet Program. # # Output: # Returns line data fields in a list array format (@output). # # # Written By: Jeff Walters at hiker_jjw@yahoo.com # Last Edit: 7/16/99 # Please report any problems to hiker_jjw@yahoo.com # ############################################################ sub SplitData { local($data_line) = @_; local($combine,$combine_trigger,$data,$temp_data,$data_length, @split_data, @output); $combine_trigger = "off"; # Remove the new line or carriage return characters. $data_line =~ s/\n+$//; $data_line =~ s/\r+$//; # First, we split the data by commas into the @split_data array. @split_data = split (/\,/, $data_line); # For each data element we will check to see if the elements need to be combined. foreach $data (@split_data) { if ($data =~ /\"/ || $combine_trigger eq "on") { $temp_data = $data; $temp_data =~ s/\"{2}//g; # Check to see if the data begins with an even or odd number of quotes if ( $temp_data =~ /^\"/ ) { $beginning_quotes = "odd" } else { $beginning_quotes = "even" } # Check to see if the data ends with an even or odd number of quotes if ( $temp_data =~ /\"$/ ) { $ending_quotes = "odd" } else { $ending_quotes = "even" } $temp_data = $data; $temp_data =~ s/\"//g; if ($temp_data eq "") { $all_quotes = "true" } else { $all_quotes = "false" } $data_length = length($data); # print "Combine \n"; # print "$beginning_quotes $ending_quotes $all_quotes
\n"; # $data contains a comma, but we do not need to combine. if ( $beginning_quotes eq "odd" && $ending_quotes eq "odd" && $all_quotes eq "false" ) { $combine_trigger = "off"; $data = substr($data,1,$length-1); $data =~ s/\"{2}/\"/g; push (@output,$data); } # $data is the beginning of a split field elsif ( $beginning_quotes eq "odd" && $ending_quotes eq "even" && $all_quotes eq "false" ) { $combine_trigger = "on"; $data = substr($data,1); $data =~ s/\"{2}/\"/g; $combine_data = $data; } # $data is a middle section of the split field elsif ( $beginning_quotes eq "even" && $ending_quotes eq "even" && $all_quotes eq "false" ) { $combine_trigger = "on"; $data =~ s/\"{2}/\"/g; $combine_data .= ",$data"; } # $data is the ending of the split field elsif ( $beginning_quotes eq "even" && $ending_quotes eq "odd" && $all_quotes eq "false" ) { $combine_trigger = "off"; $data = substr($data,0,$length-1); $data =~ s/\"{2}/\"/g; $combine_data .= ",$data"; push (@output,$combine_data); $combine_data = ""; } elsif ( $beginning_quotes eq "odd" && $ending_quotes eq "odd" && $all_quotes eq "true" ) { $data =~ s/\"//; # remove one double quote $data =~ s/\"{2}/\"/g; if ( $combine_trigger eq "off" ) { $combine_trigger = "on"; $combine_data = "$data"; } else { $combine_trigger = "off"; $combine_data .= ",$data"; push (@output, $combine_data); } } elsif ( $beginning_quotes eq "even" && $ending_quotes eq "even" && $all_quotes eq "true" ) { $data =~ s/\"{2}/\"/g; $combine_data .= ",$data"; } else { $combine_trigger = "off"; $combine_data .= "ERROR"; } } else { # print "Regular Push
\n"; push (@output, $data); } } @output; } # end of SplitData