CSV to HTML translation

From Rosetta Code
Revision as of 16:33, 30 July 2016 by Simple9371 (talk | contribs) (Undo)
Task
CSV to HTML translation
You are encouraged to solve this task according to the task description, using any language you may know.

Consider a simplified CSV format where all rows are separated by a newline and all columns are separated by commas. No commas are allowed as field data, but the data may contain other characters and character sequences that would normally be escaped when converted to HTML

The task is to create a function that takes a string representation of the CSV data and returns a text string of an HTML table representing the CSV data. Use the following data as the CSV text to convert, and show your output.

Character,Speech
The multitude,The messiah! Show us the messiah!
Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude,Who are you?
Brians mother,I'm his mother; that's who!
The multitude,Behold his mother! Behold his mother!

For extra credit, optionally allow special formatting for the first row of the table as if it is the tables header row (via <thead> preferably; CSS if you must).

Ada

Works with: Ada 2005
Library: AWS

csv2html.adb: <lang Ada>with Ada.Strings.Fixed; with Ada.Text_IO; with Templates_Parser;

procedure Csv2Html is

  use type Templates_Parser.Vector_Tag;
  Chars : Templates_Parser.Vector_Tag;
  Speeches : Templates_Parser.Vector_Tag;
  CSV_File : Ada.Text_IO.File_Type;

begin

  -- read the csv data
  Ada.Text_IO.Open (File => CSV_File,
                    Mode => Ada.Text_IO.In_File,
                    Name => "data.csv");
  -- fill the tags
  while not Ada.Text_IO.End_Of_File (CSV_File) loop
     declare
        Whole_Line : String := Ada.Text_IO.Get_Line (CSV_File);
        Comma_Pos : Natural := Ada.Strings.Fixed.Index (Whole_Line, ",");
     begin
        Chars := Chars & Whole_Line (Whole_Line'First .. Comma_Pos - 1);
        Speeches := Speeches & Whole_Line (Comma_Pos + 1 .. Whole_Line'Last);
     end;
  end loop;
  Ada.Text_IO.Close (CSV_File);
  -- build translation table and output html
  declare
     Translations : constant Templates_Parser.Translate_Table :=
       (1 => Templates_Parser.Assoc ("CHAR", Chars),
        2 => Templates_Parser.Assoc ("SPEECH", Speeches));
  begin
     Ada.Text_IO.Put_Line
       (Templates_Parser.Parse ("table.tmplt", Translations));
  end;

end Csv2Html;</lang>

table.tmplt:

<lang html5>

@@TABLE@@ @@END_TABLE@@
@_WEB_ESCAPE:CHAR_@ @_WEB_ESCAPE:SPEECH_@

</lang>

Output:

<lang html5>

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</lang>

ALGOL 68

Works with: ALGOL 68 version Revision 1 - no extensions to language used.
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny.

<lang algol68>#!/usr/local/bin/a68g --script #

[6]STRING rows := []STRING(

   "Character,Speech",
   "The multitude,The messiah! Show us the messiah!",
   "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>",
   "The multitude,Who are you?",
   "Brians mother,I'm his mother; that's who!",
   "The multitude,Behold his mother! Behold his mother!"

);

[max abs char]STRING encoded; FOR i TO UPB encoded DO encoded[i]:=REPR i OD;

  1. encoded[ABS""""] := """; optional #
 encoded[ABS "&"] := "&";
 encoded[ABS "<"] := "<";
  1. encoded[ABS ">"] := ">"; optional #

OP ENCODE = (STRING s)STRING: (

 STRING out := "";
 FOR i TO UPB s DO out+:= encoded[ABS s[i]] OD;
 out

);

PROC head = (STRING title)VOID: (

 printf((
   $"<HEAD>"l$,
     $"<TITLE>"g"</TITLE>"l$, title,
     $"<STYLE type=""text/css"">"l$,
       $"TD {background-color:#ddddff; }"l$,
       $"thead TD {background-color:#ddffdd; text-align:center; }"l$,
     $"</STYLE>"l$,
   $"</HEAD>"l$
 ))

);

  1. define HTML tags using Algol68's "reverent" block structuring #

PROC html = VOID: print(("<HTML>", new line)),

      body = VOID: print(("<BODY>", new line)),

table = VOID: print(("

", new line)), table row = VOID: print(("")), th = (STRING s)VOID: printf(($""$, s)), td = (STRING s)VOID: printf(($""$, s)), elbat row = VOID: print(("", new line)), elbat = VOID: print(("
"g""g"

", new line)),

      ydob = VOID: print(("</BODY>", new line)),
    lmth = VOID: print(("</HTML>", new line));

FILE row input; STRING row; CHAR ifs = ","; associate(row input, row); make term(row input, ifs);

html;

 head("CSV to HTML translation - Extra Credit");
 body;
   table;
     FOR nr TO UPB rows DO
       row := rows[nr];
       table row;
         on logical file end(row input, (REF FILE row input)BOOL: row end);
         FOR nf DO
           STRING field; get(row input,field);
           (nr=1|th|td)(ENCODE field);
           get(row input, space)
         OD;
         row end: reset(row input);
       elbat row
     OD;
   elbat;
 ydob;

lmth</lang>

Output:

<lang html5><HTML> <HEAD> <TITLE>CSV to HTML translation - Extra Credit</TITLE> <STYLE type="text/css"> TD {background-color:#ddddff; } thead TD {background-color:#ddffdd; text-align:center; } </STYLE> </HEAD> <BODY>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</BODY> </HTML></lang>

AutoHotkey

Very basic implementation <lang AutoHotkey>CSVData = ( Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! )

TableData := "

" Loop Parse, CSVData,`n { TableData .= "`n " Loop Parse, A_LoopField, CSV TableData .= "" TableData .= "" } TableData .= "`n
" HTMLEncode(A_LoopField) "

"

HTMLEncode(str){

  static rep := "&<lt;>gt;""quot"
  Loop Parse, rep,;
     StringReplace, str, str, % SubStr(A_LoopField, 1, 1), % "&" . SubStr(A_LoopField, 2) . ";", All
  return str

} MsgBox % clipboard := TableData</lang>

Output:
<table>
  <tr><td>Character</td><td>Speech</td></tr>
  <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr>
  <tr><td>Brians mother</td><td>&lt;angry&gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!&lt;/angry&gt;</td></tr>
  <tr><td>The multitude</td><td>Who are you?</td></tr>
  <tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr>
  <tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr>
</table>

(note the output has been modified slightly since this webpage is html.)

AutoIt

<lang AutoIt> Local $ascarray[4] = [34,38,60,62] $String = "Character,Speech" & @CRLF $String &= "The multitude,The messiah! Show us the messiah!" & @CRLF $String &= "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" & @CRLF $String &= "The multitude,Who are you?" & @CRLF $String &= "Brians mother,I'm his mother; that's who!" & @CRLF $String &= "The multitude,Behold his mother! Behold his mother!" For $i = 0 To UBound($ascarray) -1 $String = Stringreplace($String, chr($ascarray[$i]), "&#"&$ascarray[$i]&";") Next

$newstring = "

" & @CRLF $crlfsplit = StringSplit($String, @CRLF, 1) For $i = 1 To $crlfsplit[0] If $i = 1 Then $newstring &= "<thead>" & @CRLF $newstring &= "" & @CRLF $komsplit = StringSplit($crlfsplit[$i], ",") For $k = 1 To $komsplit[0] If $i = 1 Then $newstring &= "" & @CRLF

Else

$newstring &= "" & @CRLF

EndIf Next

$newstring &= "" & @CRLF If $i = 1 Then $newstring &= "</thead>" & @CRLF Next $newstring &= "
" &$komsplit[$k] & "" &$komsplit[$k] & "

"

ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $newstring = ' & $newstring & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console </lang>

Output:
<table>
<thead>
<tr>
<th>Character</th>
<th>Speech</th>
</tr>
</thead>
<tr>
<td>The multitude</td>
<td>The messiah! Show us the messiah!</td>
</tr>
<tr>
<td>Brians mother</td>
<td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td>
</tr>
<tr>
<td>The multitude</td>
<td>Who are you?</td>
</tr>
<tr>
<td>Brians mother</td>
<td>I'm his mother; that's who!</td>
</tr>
<tr>
<td>The multitude</td>
<td>Behold his mother! Behold his mother!</td>
</tr>
</table>


ANTLR

Java

<lang java> // Create an HTML Table from comma seperated values // Nigel Galloway - June 2nd., 2013 grammar csv2html;

dialog : {System.out.println("<HTML>

");}header body+{System.out.println("

</HTML>");} ; header : {System.out.println("<THEAD align=\"center\">");}row{System.out.println("</THEAD");}; body  : {System.out.println("<TBODY>");}row{System.out.println("</TBODY");}; row  : field ',' field '\r'? '\n'; field  : Field{System.out.println("" + $Field.text.replace("<","<").replace(">",">") + "");};

Field  : ~[,\n\r]+; </lang>

AWK

Works with: Gawk

Includes extra credit.
File csv2html.awk <lang awk>#!/usr/bin/awk -f BEGIN {

       FS=","

print "

" } { gsub(/</, "\\<") gsub(/>/, "\\>") gsub(/&/, "\\>") print "\t" for(f = 1; f <= NF; f++) { if(NR == 1 && header) { printf "\t\t\n", $f
               }       
else printf "\t\t\n", $f
       }       
print "\t" } END { print "
%s%s

"

} </lang>

$ awk -f csv2html.awk input.csv

<lang html5>

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother >lt;angry>gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!>lt;/angry>gt;
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</lang>

Extra credit:

$ awk -v header=1 -f csv2html.awk input.csv

<lang html5>

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother >lt;angry>gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!>lt;/angry>gt;
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</lang>

Batch File

<lang dos>

Batch Files are terrifying when it comes to string processing.
But well, a decent implementation!

@echo off

REM Below is the CSV data to be converted. REM Exactly three colons must be put before the actual line.

Character,Speech
The multitude,The messiah! Show us the messiah!
Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude,Who are you?
Brians mother,I'm his mother; that's who!
The multitude,Behold his mother! Behold his mother!

setlocal disabledelayedexpansion echo ^<table^> for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (

  set "var=%%A"
  setlocal enabledelayedexpansion
     REM The next command removes the three colons...
     set "var=!var:~3!"
     REM The following commands to the substitions per line...
     set "var=!var:&=&!"
     set "var=!var:<=<!"
     set "var=!var:>=>!"

set "var=!var:,=!"

     echo ^<tr^>^<td^>!var!^</td^>^</tr^>
  endlocal

) echo ^</table^></lang>

Output:
<table>
<tr><td>Character</td><td>Speech</td></tr>
<tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr>
<tr><td>Brians mother</td><td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr>
<tr><td>The multitude</td><td>Who are you?</td></tr>
<tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr>
<tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr>
</table>

BBC BASIC

<lang bbcbasic> DATA "Character,Speech"

     DATA "The multitude,The messiah! Show us the messiah!"
     DATA "Brian's mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>"
     DATA "The multitude,Who are you?"
     DATA "Brian's mother,I'm his mother; that's who!"
     DATA "The multitude,Behold his mother! Behold his mother!"
     DATA "***"
     
     *SPOOL CSVtoHTML.htm
     PRINT "<HTML>"
     PRINT "<HEAD>"
     PRINT "</HEAD>"
     PRINT "<BODY>"

PRINT "

" header% = TRUE REPEAT READ csv$ IF csv$ = "***" THEN EXIT REPEAT IF header% PRINT "" ELSE PRINT "" header% = FALSE UNTIL FALSE PRINT "
"; ELSE PRINT "
";
       FOR i% = 1 TO LEN(csv$)
         c$ = MID$(csv$, i%, 1)
         CASE c$ OF
WHEN ",": IF header% PRINT "
"; ELSE PRINT "";
           WHEN "<": PRINT "<";
           WHEN ">": PRINT ">";
           WHEN "&": PRINT "&";
           OTHERWISE: PRINT c$;
         ENDCASE
       NEXT i%
IF header% PRINT "

"

     PRINT "</BODY>"
     PRINT "</HTML>"
     *spool
     
     SYS "ShellExecute", @hwnd%, 0, "CSVtoHTML.htm", 0, 0, 1

</lang>

Output:
<HTML>
<HEAD>
</HEAD>
<BODY>
<table border=1 cellpadding =10 cellspacing=0>
<tr><th>Character</th><th>Speech</th></tr>
<tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr>
<tr><td>Brian's mother</td><td>&lt;angry&gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!&lt;/angry&gt;</td></tr>
<tr><td>The multitude</td><td>Who are you?</td></tr>
<tr><td>Brian's mother</td><td>I'm his mother; that's who!</td></tr>
<tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr>
</table>
</BODY>
</HTML>
Rendered output:

Bracmat

This is not the most concise solution, but it is relatively efficient. To collect the lines we use a pattern that matches a line starting from position [!p. Each time a line is matched, p is updated, the two found elements are collected and the pattern is forced to fail, so the pattern matcher finds the next line. The found rows are collected in reverse order, because prepending to a list is faster than appending. When all lines are read, the collected lines are reversed, interspersed with newline characters. Finally the predefined function toML is used to create HTML. <lang bracmat>( ( CSVtoHTML

 =   p q Character Speech swor rows row
   .   0:?p
     & :?swor:?rows
     & ( @( !arg
          :   ?
              ( [!p ?Character "," ?Speech \n [?q ?
              & !q:?p
              &     (tr.,(td.,!Character) (td.,!Speech))
                    !swor
                : ?swor
              & ~
              )
          )
       |     whl
           ' ( !swor:%?row %?swor
             & !row \n !rows:?rows
             )
         &   toML
           $ (table.,(thead.,!swor) \n (tbody.,!rows))
       )
 )

& CSVtoHTML

 $ "Character,Speech

The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! " ) </lang> Output:

<lang html>

<thead></thead> <tbody> </tbody>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Befunge

The most practical solution for Befunge was to read the CSV from stdin, so this implementation works best with command line interpreters that can accept redirected input. That said, it is still possible test with many of the GUI and online interpretors just by entering the input manually.

Note that right angle brackets are deliberately not escaped, since that is not strictly necessary for the markup to be valid.

<lang Befunge><v_>#!,#:< "

" \0 +55 v >0>::65*1+`\"~"`!*#v_4-5v > v>#^~^<v"\n" } ;
  boost::regex e1( regexes[ 0 ] ) ; 
  std::string tabletext = boost::regex_replace( csvtext , e1 ,
    replacements[ 0 ] , boost::match_default | boost::format_all ) ;
  for ( int i = 1 ; i < 5 ; i++ ) {
     e1.assign( regexes[ i ] ) ;
     tabletext = boost::regex_replace( tabletext , e1 , replacements[ i ] , boost::match_default | boost::format_all ) ;
  }
tabletext = std::string( "
" < \v-1/<>">elb"

<^ >:#,_$10 |!:<>\#v_ vv"ta" v-",":\-"&":\-"<":\<>5#05#<v+ >"/"v >#v_$$$0">dt<>dt/<"vv"tr>"+<5 v"<"< >^>\#v_$$0";pma&" v>"/<>d"v5 v , < $ > \#v_$0";tl&"v v"</t"<0 > : | ^_>#!,#:<>#<0#<\#<<< >:#,_$#^_v@ $<</lang>

Output:
<lang html5>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!
</lang>

C

<lang c>#include <stdio.h>

const char *input = "Character,Speech\n" "The multitude,The messiah! Show us the messiah!\n" "Brians mother,<angry>Now you listen here! He's not the messiah; " "he's a very naughty boy! Now go away!</angry>\n" "The multitude,Who are you?\n" "Brians mother,I'm his mother; that's who!\n" "The multitude,Behold his mother! Behold his mother!";

int main() { const char *s;

printf("\n\n\n
");

for (s = input; *s; s++) { switch(*s) {

case '\n': printf("
"); break; case ',': printf(""); break;

case '<': printf("<"); break; case '>': printf(">"); break; case '&': printf("&"); break; default: putchar(*s); } }

puts("
");

return 0; }</lang>

Output:
$ gcc -Wall -W -ansi -pedantic csv.c -o csv
$ ./csv
<lang html5>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!
</lang>

C++

<lang cpp>#include <string>

  1. include <boost/regex.hpp>
  2. include <iostream>

std::string csvToHTML( const std::string & ) ;

int main( ) {

  std::string text = "Character,Speech\n" 
                           "The multitude,The messiah! Show us the messiah!\n" 

"Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>\n" "The multitude,Who are you?\n" "Brians mother,I'm his mother; that's who!\n" "The multitude,Behold his mother! Behold his mother!\n" ;

 std::cout << csvToHTML( text ) ;
 return 0 ;

}

std::string csvToHTML( const std::string & csvtext ) {

  //the order of the regexes and the replacements is decisive!
  std::string regexes[ 5 ] = { "<" , ">" , "^(.+?)\\b" , "," , "\n" } ;
const char* replacements [ 5 ] = { "<" , ">" , "
$1" , "", "
\n" ) + tabletext ; tabletext.append( "

\n" ) ;

  return tabletext ;

}</lang>

Output:

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

C#

Simple Solution

<lang C sharp> using System; using System.Collections.Generic; using System.Linq; using System.Net;

   class Program
   {
       private static string ConvertCsvToHtmlTable(string csvText)
       {
           //split the CSV, assume no commas or line breaks in text
           List<List<string>> splitString = new List<List<string>>();
           List<string> lineSplit = csvText.Split('\n').ToList();
           foreach (string line in lineSplit)
           {
               splitString.Add(line.Split(',').ToList());
           }
           //encode text safely, and create table

string tableResult = "

"; foreach(List<string> splitLine in splitString) { tableResult += ""; foreach(string splitText in splitLine) { tableResult += "";
               }
tableResult += ""; } tableResult += "
" + WebUtility.HtmlEncode(splitText) + "

";

           return tableResult;
       }
   }

</lang>

Output:

when using the text suggested

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Extra Credit Solution

<lang C sharp>using System; using System.Linq; using System.Net;

namespace CsvToHtml {

   class Program
   {
       static void Main(string[] args)
       {
           string csv =
               @"Character,Speech

The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!";

           Console.Write(ConvertCsvToHtmlTable(csv, true));
       }
       private static string ConvertCsvToHtmlTable(string csvText, bool formatHeaders)
       {
           var rows =
               (from text in csvText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) /* Split the string by newline,
                                                                                                         * removing any empty rows. */
                select text.Split(',')).ToArray(); // Split each row by comma.

string output = "

"; // Initialize the output with the value of "
". for (int index = 0; index < rows.Length; index++) // Iterate through each row. { var row = rows[index]; var tag = (index == 0 && formatHeaders) ? "th" : "td"; /* Check if this is the first row, and if to format headers. * If so, then set the tags as table headers. * Otherwise, set the tags as table data. */ output += "\r\n\t"; // Add table row tag to output string. // Add escaped cell data with proper tags to output string for each cell in row. output = row.Aggregate(output, (current, cell) => current + string.Format("\r\n\t\t<{0}>{1}</{0}>", tag, WebUtility.HtmlEncode(cell))); output += "\r\n\t"; // Add closing table row tag to output string. } output += "\r\n

"; // Add closing table tag to output string.

           return output;
       }
   }

}</lang>

Sample HTML Output:

<lang html5>

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</lang>

CoffeeScript

Works with: node.js

<lang coffeescript>String::__defineGetter__ 'escaped', () -> this.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') // rosettacode doesn't like "

text = Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!

lines = (line.split ',' for line in text.split /[\n\r]+/g)

header = lines.shift()

console.log """

<thead>

</thead> <tbody> """

for line in lines [character, speech] = line console.log """

"""

console.log """ </tbody>

#{header[0]} #{header[1]} #{character} #{speech.escaped}

"""</lang>

Output:

<lang html5>

<thead>
 </thead>
 <tbody>
 </tbody>
Character Speech The multitude The messiah! Show us the messiah! Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude Who are you? Brians mother I'm his mother; that's who! The multitude Behold his mother! Behold his mother!

</lang>


Clojure

We assume the presence of a file, but the input could come from anywhere.

<lang csv> Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! </lang>

<lang clojure> (require 'clojure.string)

(def escapes

    {\< "<", \> ">", \& "&"})

(defn escape

     [content]
     (clojure.string/escape content escapes))

(defn tr

     [cells]

(format "%s" (apply str (map #(str "" (escape %) "") cells))))

turn a seq of seq of cells into a string.

(defn to-html

     [tbl]

(format "

<tbody>%s</tbody></thead>" (apply str (map tr tbl))))
Read from a string to a seq of seq of cells.
(defn from-csv [text] (map #(clojure.string/split % #",") (clojure.string/split-lines text))) (defn -main [] (let [lines (line-seq (java.io.BufferedReader. *in*)) tbl (map #(clojure.string/split % #",") lines)] (println (to-html tbl))) </lang>
Output:

<lang html>

<tbody></tbody></thead>

</lang>

Common Lisp

<lang lisp>(defvar *csv* "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!")

(defun split-string (string delim-char)

 (let ((result '()))
   (do* ((start 0 (1+ end))

(end (position delim-char string) (position delim-char string :start start))) ((not end) (reverse (cons (subseq string start) result)))

     (push (subseq string start end) result))))
HTML escape code modified from
http://www.gigamonkeys.com/book/practical-an-html-generation-library-the-interpreter.html

(defun escape-char (char)

 (case char
   (#\& "&")
   (#\< "<")
   (#\> ">")
   (t (format nil "&#~d;" (char-code char)))))

(defun escape (in)

 (let ((to-escape "<>&"))
   (flet ((needs-escape-p (char) (find char to-escape)))
     (with-output-to-string (out)

(loop for start = 0 then (1+ pos) for pos = (position-if #'needs-escape-p in :start start) do (write-sequence in out :start start :end pos) when pos do (write-sequence (escape-char (char in pos)) out) while pos)))))

(defun html-row (values headerp)

 (let ((tag (if headerp "th" "td")))
   (with-output-to-string (out)
(write-string "" out) (dolist (val values) (format out "<~A>~A</~A>" tag (escape val) tag)) (write-string "" out)))) (defun csv->html (csv) (let* ((lines (split-string csv #\Newline)) (cols (split-string (first lines) #\,)) (rows (mapcar (lambda (row) (split-string row #\,)) (rest lines)))) (with-output-to-string (html) (format html "
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!
~C" #\Newline) (format html "~C~A~C" #\Tab (html-row cols t) #\Newline) (dolist (row rows) (format html "~C~A~C" #\Tab (html-row row nil) #\Newline)) (write-string "

" html))))</lang>

CL-USER> (csv->html *csv*)
Output:

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

D

Translation of: C

<lang d>void main() {

   import std.stdio;
   immutable input =
       "Character,Speech\n" ~
       "The multitude,The messiah! Show us the messiah!\n" ~
       "Brians mother,<angry>Now you listen here! He's not the messiah; " ~
           "he's a very naughty boy! Now go away!</angry>\n" ~
       "The multitude,Who are you?\n" ~
       "Brians mother,I'm his mother; that's who!\n" ~
       "The multitude,Behold his mother! Behold his mother!";
   "<html>\n<head><meta charset=\"utf-8\"></head>\n<body>\n\n".write;

"

\n<thead>\n \n \n</thead>\n<tbody>\n \n</tbody>\n
".write;
   bool theadDone = false;
   foreach (immutable c; input) {
       switch(c) {
           case '\n':
               if (theadDone) {
"
".write;
               } else {
"
".write;
                   theadDone = true;
               }
               break;
case ',': "
".write; break;
           case '<':  "<".write;      break;
           case '>':  ">".write;      break;
           case '&':  "&".write;     break;
           default:   c.write;           break;
       }
   }
"

\n\n</body></html>".write;

}</lang>

Output:

<lang html5><html> <head><meta charset="utf-8"></head> <body>

<thead>

</thead> <tbody>

</tbody>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body> </html></lang>

Delphi

This solution solves both the basic and extra credit tasks.

<lang Delphi>program csv2html;

{$APPTYPE CONSOLE}

uses

 SysUtils,
 Classes;

const

 // Carriage Return/Line Feed
 CRLF    = #13#10;
 // The CSV data
 csvData =
 'Character,Speech'+CRLF+
 'The multitude,The messiah! Show us the messiah!'+CRLF+
 'Brians mother,<angry>Now you listen here! Hes not the messiah; hes a very naughty boy! Now go away!</angry>'+CRLF+
 'The multitude,Who are you?'+CRLF+
 'Brians mother,Im his mother; thats who!'+CRLF+
 'The multitude,Behold his mother! Behold his mother!';
 // HTML header
 htmlHead =
 '<!DOCTYPE html'+CRLF+
 'PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'+CRLF+
 '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+CRLF+
 '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">'+CRLF+
 '<head>'+CRLF+
 '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />'+CRLF+
 '<title>CSV-to-HTML Conversion</title>'+CRLF+
 '<style type="text/css">'+CRLF+
 'body {font-family:verdana,helvetica,sans-serif;font-size:100%}'+CRLF+
 'table {width:70%;border:0;font-size:80%;margin:auto}'+CRLF+
 'th,td {padding:4px}'+CRLF+
 'th {text-align:left;background-color:#eee}'+CRLF+
 'th.c {width:15%}'+CRLF+
 'td.c {width:15%}'+CRLF+
 '</style>'+CRLF+
 '</head>'+CRLF+
 '<body>'+CRLF;
 // HTML footer
 htmlFoot =
 '</body>'+CRLF+
 '</html>';

{ Function to split a string into a list using a given delimiter } procedure SplitString(S, Delim: string; Rslt: TStrings); var

 i: integer;
 fld: string;

begin

 fld := ;
 for i := Length(S) downto 1 do
   begin
     if S[i] = Delim then
       begin
         Rslt.Insert(0,fld);
         fld := ;
       end
       else
        fld := S[i]+fld;
   end;
 if (fld <> ) then
     Rslt.Insert(0,fld);

end;

{ Simple CSV parser with option to specify that the first row is a header row } procedure ParseCSV(const csvIn: string; htmlOut: TStrings; FirstRowIsHeader: Boolean = True); const

rowstart = ''; rowend = ''; cellendstart = ''; hcellendstart = ''; hrowstart = ''; hrowend = ''; var tmp,pieces: TStrings; i: Integer; begin // HTML header htmlOut.Text := htmlHead + CRLF + CRLF; // Start the HTML table htmlOut.Text := htmlOut.Text + '

' + CRLF; // Create stringlist tmp := TStringList.Create; try // Assign CSV data to stringlist and fix occurences of '<' and '>' tmp.Text := StringReplace(csvIn,'<','<',[rfReplaceAll]); tmp.Text := StringReplace(tmp.Text,'>','>',[rfReplaceAll]); // Create stringlist to hold the parts of the split data pieces := TStringList.Create; try // Loop through the CSV rows for i := 0 to Pred(tmp.Count) do begin // Split the current row SplitString(tmp[i],',',pieces); // Check if first row and FirstRowIsHeader flag set if (i = 0) and FirstRowIsHeader then // Render HTML htmlOut.Text := htmlOut.Text + hrowstart + pieces[0] + hcellendstart + pieces[1] + hrowend + CRLF else htmlOut.Text := htmlOut.Text + rowstart + pieces[0] + cellendstart + pieces[1] + rowend + CRLF; end; // Finish the HTML table and end the HTML page htmlOut.Text := htmlOut.Text + '

' + CRLF + htmlFoot;

   finally
     pieces.Free;
   end;
 finally
   tmp.Free;
 end;

end;

var

 HTML: TStrings;

begin

 // Create stringlist to hold HTML output
 HTML := TStringList.Create;
 try
   Writeln('Basic:');
   Writeln();
   // Load and parse the CSV data
   ParseCSV(csvData,HTML,False);
   // Output the HTML to the console
   Writeln(HTML.Text);
   // Save the HTML to a file (in application's folder)
   HTML.SaveToFile('csv2html_basic.html');
   Writeln();
   Writeln('=====================================');
   Writeln();
   HTML.Clear;
   Writeln('Extra Credit:');
   Writeln();
   // Load and parse the CSV data
   ParseCSV(csvData,HTML,True);
   // Output the HTML to the console
   Writeln(HTML.Text);
   // Save the HTML to a file (in application's folder)
   HTML.SaveToFile('csv2html_extra.html');
   Writeln();
   Writeln('=====================================');
 finally
   HTML.Free;
 end;
 // Keep console window open
 Readln;

end.</lang>

Basic output:

<lang html5><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> <title>CSV-to-HTML Conversion</title> <style type="text/css"> body {font-family:verdana,helvetica,sans-serif;font-size:100%} table {width:70%;border:0;font-size:80%;margin:auto} th,td {padding:4px} th {text-align:left;background-color:#eee} th.c {width:15%} td.c {width:15%} </style> </head> <body>


CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body> </html></lang>

Extra credit output:

<lang html5><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> <title>CSV-to-HTML Conversion</title> <style type="text/css"> body {font-family:verdana,helvetica,sans-serif;font-size:100%} table {width:70%;border:0;font-size:80%;margin:auto} th,td {padding:4px} th {text-align:left;background-color:#eee} th.c {width:15%} td.c {width:15%} </style> </head> <body>


CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body> </html></lang>

EchoLisp

<lang scheme>

CSV -> LISTS

(define (csv->row line) (string-split line ",")) (define (csv->table csv) (map csv->row (string-split csv "\n")))

LISTS->HTML

(define html 'html) (define (emit-tag tag html-proc content ) (if (style tag) (push html (format "<%s style='%a'>" tag (style tag))) (push html (format "<%s>" tag ))) (html-proc content) (push html (format "</%s> " tag )))

html procs
1 tag, 1 proc

(define (h-raw content) (push html (format "%s" content))) (define (h-header headers) (for ((h headers)) (emit-tag 'th h-raw h))) (define (h-row row) (for ((item row)) (emit-tag 'td h-raw item))) (define (h-table table ) (emit-tag 'tr h-header (first table)) (for ((row (rest table))) (emit-tag 'tr h-row row)))

(define (html-dump) (string-join (stack->list html) " "))

STYLES

(style 'td "text-align:left") (style 'table "border-spacing: 10px;border:28px ridge orange") ;; special biblical border (style 'th "color:blue;") </lang>

Output:

<lang scheme>

changed <angry> to to show that html tags inside text are correctly transmitted.

(define MontyPython #<<

   Character,Speech 
   The multitude,The messiah! Show us the messiah! 
   Brians mother,Now you listen here! He's not the messiah; he's a very naughty boy! Now go away! 
   The multitude,Who are you? 
   Brians mother,I'm his mother; that's who! 
   The multitude,Behold his mother! Behold his mother! 

>>#)

(define (task speech) (define table (csv->table speech)) (stack html) (emit-tag 'table h-table table) (html-dump))

(task MontyPython) </lang>

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!


Erlang

Using functions from Create_an_HTML_table <lang Erlang> -module( csv_to_html ).

-export( [table_translation/1, task/0] ).

table_translation( CSV ) -> [Headers | Contents] = [string:tokens(X, ",") || X <- string:tokens( CSV, "\n")], Table = create_html_table:html_table( [{border, "1"}, {cellpadding, "10"}], Headers, Contents ), create_html_table:external_format( Table ).

task() -> table_translation( csv() ).


csv() -> "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!". </lang>

Output:
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

Euphoria

Translation of: C
Works with: Euphoria version 4.*

<lang euphoria>constant input = "Character,Speech\n" &

   "The multitude,The messiah! Show us the messiah!\n" &
   "Brians mother,<angry>Now you listen here! He's not the messiah; " &
       "he's a very naughty boy! Now go away!</angry>\n" &
   "The multitude,Who are you?\n" &
   "Brians mother,I'm his mother; that's who!\n" &
   "The multitude,Behold his mother! Behold his mother!"

puts(1,"

\n\n\n
")

for i = 1 to length(input) do

   switch input[i] do
case '\n' then puts(1,"
") case ',' then puts(1,"")
       case '<'  then puts(1,"<")
       case '>'  then puts(1,">")
       case '&'  then puts(1,"&")
       case else puts(1,input[i])
   end switch

end for

puts(1,"

")</lang>

Output:

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

F#

Use .NET XmlWriter. Stylesheet styling is applied only when command line option -h ist given. <lang fsharp>open System open System.Text open System.Xml

let data = """ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! """

let csv =

   Array.map
       (fun (line : string) -> line.Split(','))
       (data.Trim().Split([|'\n';'\r'|],StringSplitOptions.RemoveEmptyEntries))


[<EntryPoint>] let main argv =

   let style = argv.Length > 0 && argv.[0] = "-h"
   Console.OutputEncoding <- UTF8Encoding()
   let xs = XmlWriterSettings()
   xs.Indent <- true   // be friendly to humans
   use x = XmlWriter.Create(Console.Out, xs)
   x.WriteStartDocument()
   x.WriteDocType("HTML", null, null, null)    // HTML5
   x.WriteStartElement("html")
   x.WriteStartElement("head")
   x.WriteElementString("title", "Rosettacode - CSV to HTML translation")
   if style then
       x.WriteStartElement("style"); x.WriteAttributeString("type", "text/css")
       x.WriteString("""
           table { border-collapse: collapse; }
           td, th { border: 1px solid black; padding: .25em}
           th { background-color: #EEE; }
           tbody th { font-weight: normal; font-size: 85%; }
       """)        
       x.WriteEndElement() // style
   x.WriteEndElement() // head
   x.WriteStartElement("body")
   x.WriteStartElement("table")
   x.WriteStartElement("thead"); x.WriteStartElement("tr")
   for part in csv.[0] do x.WriteElementString("th", part)
   x.WriteEndElement(); x.WriteEndElement() // tr thead
   x.WriteStartElement("tbody")
   for line in csv.[1..] do
       x.WriteStartElement("tr")
       x.WriteElementString("th", line.[0])
       x.WriteElementString("td", line.[1])
       x.WriteEndElement() // tr
   x.Close()
   0</lang>
Output:

(stylesheet version)

<lang html5><?xml version="1.0" encoding="utf-8"?> <!DOCTYPE HTML > <html>

 <head>
   <title>Rosettacode - CSV to HTML translation</title>
   <style type="text/css">
           table { border-collapse: collapse; }
           td, th { border: 1px solid black; padding: .25em}
           th { background-color: #EEE; }
           tbody th { font-weight: normal; font-size: 85%; }
       </style>
 </head>
 <body>
<thead> </thead> <tbody> </tbody>
Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!
 </body>
</html></lang>

Fortran

The plan here is to scan each line for commas to find the splitters between texts, then write the texts out with suitable td and /td swaddling. Text presented as a quoted string (that could thereby contain a comma that is not a delimiter) is explicitly not recognised and apostrophes are apostrophes. Similarly, no attempt is made to recognise characters within the texts that might cause trouble, either because they will not elicit the same glyph when rendered from .html, or because they trigger interpretative action rather than be passed through as-is. Thus the lurking "angry" markings in the texts are not given special conversion. Further, leading and trailing spaces in each text are not trimmed off as the .html rendition process ignores them anyway. To remove them would seem to be easy enough via the special intrinsic function TRIM (available in F90) were it not that it trims off only trailing spaces. Otherwise one could mess with arrays such as IST and LST to finger the first and last character position of each text and deal patiently with the complications attendant on entirely blank or null strings when scanning the input line to determine the values.

The source is only just F90. It uses an array with a specified lower bound (of zero) - with older Fortran you could play with EQUIVALENCE or else diligently remember the offset. More difficult is the arrangement for ascertaining the length of a record as it is being read, with protection against overflowing the scratchpad should it be longer than is allowed for. This requires the Q format code, and was a common extension to F77. As usual, in the absence of help from the filesystem, the length of the longest record could only be determined through reading the entire file, and for this example it is not worth the annoyance. In the absence of the Q format feature, the input record would be read into ALINE with possibly many trailing spaces added to fill out the scratchpad; more time would be lost in scanning backwards to find the last non-blank. Should a record be longer than the scratchpad then its tail end would be lost and no remark made. Some systems (such as Snobol) are able to read a record and prepare a text variable of the correct size for that record, whatever its length (up to some integer limit such as 65535, or even more) but Fortran is not one such.

The key statement is the compound WRITE statement and its associated FORMAT, and for non-furrytranners these proceedings may be obscure. A WRITE statement accepts a list of items to be written in the usual manner, and an item is usually the name of a variable or an expression (such as 2*X + 1), but it can also be an implied DO-list. In this case the item is enclosed in brackets, and within them starts with an item list followed by a comma and a DO-expression, as in (a,b,c, I = 1,N) where a, b and c constitute a three-element list of items - any of which could themselves be an implied DO-list if nested lists were desired. Thus, by one means or another, the WRITE statement produces a sequence of values (of various types) to be sent forth. In association with the list of entries in the nominated FORMAT statement: processing proceeds in parallel through both lists in the manner of coroutines, not sequentially. It is possible with a READ statement that a value just read adjusts a part of a FORMAT statement not yet encountered during the processing of the READ statement. For instance FORMAT 13 could have <NCOLS> instead of 666 as its repeat count, but this is an extension to F77 and avoided here to stick with older abilities except where inconvenient.

Thus, the entire line for a table row can be written in one go, starting with the tr then many repetitions of (WOT,text, WOT), with each starting and ending WOT appropriately encased by < and > and / characters supplied by the FORMAT. This repeated pattern is unsuitable for starting the line (so the tr is provided by the FORMAT, with indentation) because then it would be out of step, but happily, after the last text is rolled, the required /tr can be sent to use the format codes that would normally be used for the start of the next text. Humm. If there were to be 666 texts to roll, this will exhaust the FORMAT statement and it will write the current line out and start a fresh one, resuming at the rightmost ( in the FORMAT specification. This rule does not always prove convenient so I'd prefer the vertical bar usage of musical notation to mark the resumption location. Interpreters of html do not care about layout but humans do, so, just in case, the repeat count should be 667 (or <NCOLS + 1>), or, if <NCOLS> were used, there could follow a ,A in the FORMAT, or, the "/tr" could be removed from the WRITE and appended to end the FORMAT just as at its start, but enough.

The check for a comma is not ALINE(I:I).EQ."," because in other work this usage has been found to evoke astoundingly bad code, notably that both appearances of "I" are checked as being within bounds, and, the length is calculated by subtracting the "first" (I) from the "last" (also I) at run time! At least by the COMPAQ F90/95 compiler. By contrast, the ICHAR usage, which can only be for a single character, lacks this madness and far superior speed results. Not important in this example, but it explains why this puzzling usage appeared in a prog. at the Culham Science Centre in source from an IBM mainframe. <lang Fortran>

     SUBROUTINE CSVTEXT2HTML(FNAME,HEADED)	!Does not recognise quoted strings.

Converts without checking field counts, or noting special characters.

      CHARACTER*(*) FNAME	!Names the input file.
      LOGICAL HEADED		!Perhaps its first line is to be a heading.
      INTEGER MANY		!How long is a piece of string?
      PARAMETER (MANY=666)	!This should suffice.
      CHARACTER*(MANY) ALINE	!A scratchpad for the input.
      INTEGER MARK(0:MANY + 1)	!Fingers the commas on a line.
      INTEGER I,L,N		!Assistants.
      CHARACTER*2 WOT(2)	!I don't see why a "table datum" could not be for either.
      PARAMETER (WOT = (/"th","td"/))	!A table heding or a table datum
      INTEGER IT		!But, one must select appropriately.
      INTEGER KBD,MSG,IN		!A selection.
      COMMON /IOUNITS/ KBD,MSG,IN	!The caller thus avoids collisions.
       OPEN(IN,FILE=FNAME,STATUS="OLD",ACTION="READ",ERR=661)	!Go for the file.
       WRITE (MSG,1)			!Start the blather.

1 FORMAT ("

") !By stating that a table follows. MARK(0) = 0 !Syncopation for the comma fingers. N = 0 !No records read. 10 READ (IN,11,END = 20) L,ALINE(1:MIN(L,MANY)) !Carefully acquire some text. 11 FORMAT (Q,A) !Q = number of characters yet to read, A = characters. N = N + 1 !So, a record has been read. IF (L.GT.MANY) THEN !Perhaps it is rather long? WRITE (MSG,12) N,L,MANY !Alas! 12 FORMAT ("Line ",I0," has length ",I0,"! My limit is ",I0) !Squawk/ L = MANY !The limit actually read. END IF !So much for paranoia. IF (N.EQ.1 .AND. HEADED) THEN !Is the first line to be treated specially? WRITE (MSG,*) "<tHead>" !Yep. Nominate a heading. IT = 1 !And select "th" rather than "td". ELSE !But mostly, IT = 2 !Just another row for the table. END IF !So much for the first line. NCOLS = 0 !No commas have been seen. DO I = 1,L !So scan the text for them. IF (ICHAR(ALINE(I:I)).EQ.ICHAR(",")) THEN !Here? NCOLS = NCOLS + 1 !Yes! MARK(NCOLS) = I !The texts are between commas. END IF !So much for that character. END DO !On to the next. NCOLS = NCOLS + 1 !This is why the + 1 for the size of MARK. MARK(NCOLS) = L + 1 !End-of-line is as if a comma was one further along. WRITE (MSG,13) !Now roll all the texts. 1 (WOT(IT), !This starting a cell, 2 ALINE(MARK(I - 1) + 1:MARK(I) - 1), !This being the text between the commas, 3 WOT(IT), !And this ending each cell. 4 I = 1,NCOLS), !For this number of columns. 5 "/tr" !And this ends the row. 13 FORMAT (" ",666("<",A,">",A,"</",A,">")) !How long is a piece of string? IF (N.EQ.1 .AND. HEADED) WRITE (MSG,*) "</tHead>" !Finish the possible header. GO TO 10 !And try for another record. 20 CLOSE (IN) !Finished with input. WRITE (MSG,21) !And finished with output. 21 FORMAT ("

") !This writes starting at column one.

      RETURN			!Done!

Confusions.

 661   WRITE (MSG,*) "Can't open file ",FNAME	!Alas.
     END			!So much for the conversion.
     INTEGER KBD,MSG,IN
     COMMON /IOUNITS/ KBD,MSG,IN
     KBD = 5	!Standard input.
     MSG = 6	!Standard output.
     IN = 10	!Some unspecial number.
     CALL CSVTEXT2HTML("Text.csv",.FALSE.)	!The first line is not special.
     WRITE (MSG,*)
     CALL CSVTEXT2HTML("Text.csv",.TRUE.)	!The first line is a heading.
     END

</lang>

Output:
<Table border=1>
 <tr><td>Character</td><td>Speech</td></tr>
 <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr>
 <tr><td>Brian's mother</td><td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr>
 <tr><td>The multitude</td><td>Who are you?</td></tr>
 <tr><td>Brian's mother</td><td>I'm his mother; that's who!</td></tr>
 <tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr>
</Table>

<Table border=1>
 <tHead>
 <tr><th>Character</th><th>Speech</th></tr>
 </tHead>
 <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr>
 <tr><td>Brian's mother</td><td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr>
 <tr><td>The multitude</td><td>Who are you?</td></tr>
 <tr><td>Brian's mother</td><td>I'm his mother; that's who!</td></tr>
 <tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr>

And interpreted, first with no special heading:

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brian's mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brian's motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!
<tHead>
</tHead>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brian's mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brian's motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

Go

<lang go>package main

import (

   "bytes"
   "encoding/csv"
   "fmt"
   "html/template"

)

var c = `Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!`

func main() {

   if h, err := csvToHtml(c); err != nil {
       fmt.Println(err)
   } else {
       fmt.Print(h)
   }

}

func csvToHtml(c string) (string, error) {

   data, err := csv.NewReader(bytes.NewBufferString(c)).ReadAll()
   if err != nil {
       return "", err
   }
   var b bytes.Buffer

err = template.Must(template.New("").Parse(`

{{.}}

Template:Range .

Template:Range .

Template:End

Template:End

`)).Execute(&b, data)

   return b.String(), err

}</lang> Extra credit version accepts -h command line option to do the special formatting for the heading line. <lang go>package main

import (

   "bytes"
   "encoding/csv"
   "flag"
   "fmt"
   "html/template"

)

var csvStr = `Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!`

func main() {

   headings := flag.Bool("h", false, "format first row as column headings")
   flag.Parse()
   if html, err := csvToHtml(csvStr, *headings); err != nil {
       fmt.Println(err)
   } else {
       fmt.Print(html)
   }

}

func csvToHtml(csvStr string, headings bool) (string, error) {

   data, err := csv.NewReader(bytes.NewBufferString(csvStr)).ReadAll()
   if err != nil {
       return "", err
   }
   tStr := tPlain
   if headings {
       tStr = tHeadings
   }
   var b bytes.Buffer
   err = template.Must(template.New("").Parse(tStr)).Execute(&b, data)
   return b.String(), err

}

const (

tPlain = `

{{.}}

Template:Range .

Template:Range .

Template:End

Template:End

`

tHeadings = `

<thead>
  </thead>
  <tbody>Template:EndTemplate:End
  </tbody>Template:End
{{.}}
{{.}}

Template:If .

Template:Range $x, $e := .

Template:If $x

Template:Range .

Template:End

Template:Else

Template:Range .

Template:End

` )</lang>

Output:

Extra credit version with -h

<lang html>

<thead>
  </thead>
  <tbody>
  </tbody>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Basic version, or extra credit version without -h

<lang html>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Groovy

Solution #1: Nested GStrings

Brute force solution using nested GStrings. It solves both the basic and extra credit tasks. <lang groovy>def formatCell = { cell ->

"${cell.replaceAll('&','&').replaceAll('<','<')}"

}

def formatRow = { row ->

"""${row.split(',').collect { cell -> formatCell(cell) }.join()} """ } def formatTable = { csv, header=false -> def rows = csv.split('\n').collect { row -> formatRow(row) } header \  ? """

<thead> ${rows[0]}</thead> <tbody> ${rows[1..-1].join(

)}</tbody>

""" \

       : """
${rows.join(

)}

""" }

def formatPage = { title, csv, header=false -> """<html> <head> <title>${title}</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>${formatTable(csv, header)}</body> </html>""" }</lang>

Test: <lang groovy>def csv = Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!

println 'Basic:' println '-----------------------------------------' println (formatPage('Basic', csv)) println '-----------------------------------------' println() println() println 'Extra Credit:' println '-----------------------------------------' println (formatPage('Extra Credit', csv, true)) println '-----------------------------------------'</lang>

Basic output:
<lang html5><html>

<head> <title>Basic</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body>

</html></lang>


Appearance as rendered in Google Chrome.

Extra Credit output:
<lang html5><html>

<head> <title>Extra Credit</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>

<thead>

</thead> <tbody>

</tbody>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body>

</html></lang>


Appearance as rendered in Google Chrome.

Solution #2: MarkupBuilder

A much cleaner solution using the Groovy XML MarkupBuilder class. It solves both the basic and extra credit tasks. <lang groovy>import groovy.xml.MarkupBuilder

def formatRow = { doc, row ->

   doc.tr { row.each { cell -> td { mkp.yield(cell) } } }

}

def formatPage = { titleString, csv, header=false ->

   def writer = new StringWriter()
   def doc = new MarkupBuilder(writer)
   def rows = csv.split('\n').collect { row -> row.split(',') }
   doc.html {
       head {
           title (titleString)
           style (type:"text/css") { 
               mkp.yield(
                   td {background-color:#ddddff; }
                   thead td {background-color:#ddffdd; text-align:center; }
               )
           }
       }
       body {
           table {
               header && thead { formatRow(doc, rows[0]) }
               header && tbody { rows[1..-1].each { formatRow(doc, it) } }
               header || rows.each { formatRow(doc, it) }
           }
       }
   }
   writer.toString()

}</lang>

Test:
The interface is the same for both solutions, so we just reuse the same test as before.

Basic output:
<lang html5><html>
 <head>
   <title>Basic</title>
   <style type='text/css'>
                   td {background-color:#ddddff; }
                   thead td {background-color:#ddffdd; text-align:center; }
               </style>
 </head>
 <body>
Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!
 </body>
</html></lang>

The HTML for this solution looks superficially different than that from the GString solution, but the appearance as rendered in Google Chrome is identical.

Extra Credit output:

<lang html5><html>
 <head>
   <title>Extra Credit</title>
   <style type='text/css'>
                   td {background-color:#ddddff; }
                   thead td {background-color:#ddffdd; text-align:center; }
               </style>
 </head>
 <body>
<thead> </thead> <tbody> </tbody>
Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!
 </body>
</html></lang>

The HTML for this solution looks superficially different than that from the GString solution, but the appearance as rendered in Google Chrome is identical.

Haskell

Simple solution <lang haskell>--import Data.List.Split (splitOn) -- if the import is available splitOn :: Char -> String -> [String] -- otherwise splitOn delim = foldr (\x rest ->

                       if x == delim then "" : rest
                       else (x:head rest):tail rest) [""]

htmlEscape :: String -> String htmlEscape = concatMap escapeChar

             where escapeChar '<' = "<"
                   escapeChar '>' = ">"
                   escapeChar '&' = "&"
                   escapeChar '"' = """ --"
                   escapeChar c   = [c]

toHtmlRow :: [String] -> String

toHtmlRow [] = "" toHtmlRow cols = let htmlColumns = concatMap toHtmlCol cols in "\n" ++ htmlColumns ++ "" where toHtmlCol x = " " ++ htmlEscape x ++ "\n"

csvToTable :: String -> String csvToTable csv = let rows = map (splitOn ',') $ lines csv

                    html = unlines $ map toHtmlRow rows

in "

\n" ++ html ++ "

"

main = interact csvToTable</lang>

Compact version <lang haskell>import Data.List (unfoldr) split p = unfoldr (\s -> case dropWhile p s of [] -> Nothing

                                              ss -> Just $ break p ss)

main = interact (\csv -> "

\n" ++ (unlines $ map ((\cols -> "\n" ++ (concatMap (\x -> " \n") cols) ++ "") . split (==',')) $ lines csv) ++ "
" ++ concatMap (\c ->
           case c of {'<' -> "<"; '>' -> ">";

'&' -> "&"; '"' -> """; _ -> [c]}) x

++ "

")</lang>

Output
<lang html5>
Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!
</lang>

Icon and Unicon

This solution for the extra credit works in both Icon and Unicon. The simple CSV is read from standard input and written to standard output. The presence/abscend of "-heading" in the argument list sets the variable thead to the procedure writes or a 1 (for more on this see Introduction to Icon/Unicon - Conjunction yielding different results).

<lang Icon>procedure main(arglist)

   pchar := &letters ++ &digits ++ '!?;. '  # printable chars

write("

") firstHead := (!arglist == "-heading") tHead := write while row := trim(read()) do { if \firstHead then write(" <THEAD>") else tHead(" <TBODY>") writes(" ") if (\firstHead) := &null then write(" </THEAD>\n <TBODY>") tHead := 1 } write(" </TBODY>") write("
")
      while *row > 0 do
row ?:= ( (=",",writes("
")) |
                        writes( tab(many(pchar)) |
                        ("&#" || ord(move(1))) ),   tab(0))
write("

")

end</lang>

Output:

<lang html5>

<THEAD>
   </THEAD>
   <TBODY>
  </TBODY>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother&#60angry&#62Now you listen here! He&#39s not the messiah; he&#39s a very naughty boy! Now go away!&#60&#47angry&#62
The multitudeWho are you?
Brians motherI&#39m his mother; that&#39s who!
The multitudeBehold his mother! Behold his mother!

</lang>

J

Solution (extra credit) <lang j>require 'strings tables/csv' encodeHTML=: ('&';'&';'<';'<';'>';'>')&stringreplace

tag=: adverb define

 'starttag endtag'=.m
 (,&.>/)"1 (starttag , ,&endtag) L:0 y

)

markupCells=: ('';'') tag markupHdrCells=: ('';'') tag markupRows=: ('';'',LF) tag markupTable=: (('

',LF);'

') tag

makeHTMLtablefromCSV=: verb define

 0 makeHTMLtablefromCSV y             NB. default left arg is 0 (no header row)
 t=. fixcsv encodeHTML y
 if. x do. t=. (markupHdrCells@{. , markupCells@}.) t
     else. t=. markupCells t
 end.
 ;markupTable markupRows t

)</lang>

For those interested, equivalent tacit versions of tag and makeHTMLtablefromCSV are: <lang j>tag=: adverb def '[: (,&.>/)"1 m&(0&{::@[ , 1&{::@[ ,~ ]) L:0@]' makeHTMLtablefromCSV6=: 0&$: : ([: ; markupTable@markupRows@([ markupCells`(markupHdrCells@{. , markupCells@}.)@.[ fixcsv@encodeHTML))</lang>

Example <lang j> CSVstrng=: noun define Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! )

  1 makeHTMLtablefromCSV CSVstrng</lang>
HTML output:

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Java

Solution including simple and extra credit version

for simple solution  : java -cp . Csv2Html < text.csv

for extended solution: java -cp . Csv2Html header < text.csv

<lang java>import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream;

class Csv2Html {

public static String escapeChars(String lineIn) { StringBuilder sb = new StringBuilder(); int lineLength = lineIn.length(); for (int i = 0; i < lineLength; i++) { char c = lineIn.charAt(i); switch (c) { case '"': sb.append("""); break; case '&': sb.append("&"); break; case '\: sb.append("'"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; default: sb.append(c); } } return sb.toString(); }

public static void tableHeader(PrintStream ps, String[] columns) {

ps.print(""); for (int i = 0; i < columns.length; i++) { ps.print("");

ps.print(columns[i]);

ps.print(""); } ps.println(""); } public static void tableRow(PrintStream ps, String[] columns) { ps.print(""); for (int i = 0; i < columns.length; i++) { ps.print("");

ps.print(columns[i]);

ps.print(""); } ps.println(""); } public static void main(String[] args) throws Exception { boolean withTableHeader = (args.length != 0); InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); PrintStream stdout = System.out; stdout.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); stdout.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); stdout.println("<head><meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\"/>"); stdout.println("<title>Csv2Html</title>"); stdout.println("<style type=\"text/css\">"); stdout.println("body{background-color:#FFF;color:#000;font-family:OpenSans,sans-serif;font-size:10px;}"); stdout.println("table{border:0.2em solid #2F6FAB;border-collapse:collapse;}"); stdout.println("th{border:0.15em solid #2F6FAB;padding:0.5em;background-color:#E9E9E9;}"); stdout.println("td{border:0.1em solid #2F6FAB;padding:0.5em;background-color:#F9F9F9;}</style>"); stdout.println("</head><body>

Csv2Html

"); stdout.println("

"); String stdinLine; boolean firstLine = true; while ((stdinLine = br.readLine()) != null) { String[] columns = escapeChars(stdinLine).split(","); if (withTableHeader == true && firstLine == true) { tableHeader(stdout, columns); firstLine = false; } else { tableRow(stdout, columns); } } stdout.println("

</body></html>");

} } </lang>

simple solution:

<lang html5><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> <title>Csv2Html</title> <style type="text/css"> body{background-color:#FFF;color:#000;font-family:OpenSans,sans-serif;font-size:10px;} table{border:0.2em solid #2F6FAB;border-collapse:collapse;} th{border:0.15em solid #2F6FAB;padding:0.5em;background-color:#E9E9E9;} td{border:0.1em solid #2F6FAB;padding:0.5em;background-color:#F9F9F9;}</style>

</head><body>

Csv2Html

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body></html></lang>

extended:

<lang html5><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> <title>Csv2Html</title> <style type="text/css"> body{background-color:#FFF;color:#000;font-family:OpenSans,sans-serif;font-size:10px;} table{border:0.2em solid #2F6FAB;border-collapse:collapse;} th{border:0.15em solid #2F6FAB;padding:0.5em;background-color:#E9E9E9;} td{border:0.1em solid #2F6FAB;padding:0.5em;background-color:#F9F9F9;}</style>

</head><body>

Csv2Html

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</body></html></lang>

JavaScript

<lang JavaScript>var csv = "Character,Speech\n" + "The multitude,The messiah! Show us the messiah!\n" + "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>\n" + "The multitude,Who are you?\n" + "Brians mother,I'm his mother; that's who!\n" + "The multitude,Behold his mother! Behold his mother!";

var lines = csv.replace(/&/g, '&')

   .replace(/</g, '<')
   .replace(/>/g, '>')
   .replace(/"/g, '"')
   .split(/[\n\r]/)
   .map(function(line) { return line.split(',')})

.map(function(row) {return '\t\t' + row[0] + '' + row[1] + '';}); console.log('

\n\t<thead>\n' + lines[0] + '\n\t</thead>\n\t<tbody>\n' + lines.slice(1).join('\n') + '\t</tbody>\n

');

</lang>

<lang html5>

<thead>
 </thead>
 <tbody>
 </tbody>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

Output:

<lang html5>

<thead>

</thead> <tbody>

</tbody>
CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitudeWho are you?
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

jq

We will assume the input is in a file named csv2html.csv, and that the jq program as given below is in a file named csv2html.jqn. To simplify things, we will invoke the jq processor twice -- the first invocation simply converts the text input into a sequence of JSON strings: <lang jq>jq -R . csv2html.csv | jq -r -s -f csv2html.jq </lang><lang jq>def headerrow2html:

[" <thead> "] + (split(",") | map(" \(@html)")) + [ " </thead>" ]

def row2html: [" "] + (split(",") | map(" \(@html)")) + [ " " ]

def csv2html: def rows: reduce .[] as $row ([]; . + ($row | row2html)); ["

"] + (.[0] | headerrow2html) + (.[1:] | rows) + [ "

"]

csv2html | .[]</lang>

Output

<lang html5>

<thead> </thead>
Character Speech
The multitude The messiah! Show us the messiah!
Brians mother <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</lang>

Liberty BASIC

<lang lb>

   newline$ ="|"
   '   No escape behaviour, so can't refer to '/n'.
   '   Generally imported csv would have separator CR LF; easily converted first if needed
   csv$ ="Character,Speech"                                                                                        +newline$+_
   "The multitude,The messiah! Show us the messiah!"                                                               +newline$+_
   "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" +newline$+_
   "The multitude,Who are you?"                                                                                    +newline$+_
   "Brians mother,I'm his mother; that's who!"                                                                     +newline$+_
   "The multitude,Behold his mother! Behold his mother!"
   print "<HTML>"
   print "<HEAD>"
   print "</HEAD>"
   print "<BODY>"

print "

CSV to HTML translation

" print "

" print "": print "" print "
"
   for i =1 to len( csv$)
       c$ =mid$( csv$, i, 1)
       select case c$
case "|": print "
" case ",": print "";
       case "<":  print "&"+"lt;";
       case ">":  print "&"+"gt;";
       case "&":  print "&"+"amp;";
       case else:   print c$;
       end select
   next i
print "

"

   print "</BODY>"
   print "</HTML>"
   end

</lang>

Output:
<HTML>
<HEAD>
</HEAD>
<BODY>
<center><H1>CSV to HTML translation </H1></center>
<table border=1 cellpadding =10>
<tr><td>
Character</td><td>Speech</td></tr>
<tr><td>
The multitude</td><td>The messiah! Show us the messiah!</td></tr>
<tr><td>
Brians mother</td><td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr>
<tr><td>
The multitude</td><td>Who are you?</td></tr>
<tr><td>
Brians mother</td><td>I'm his mother; that's who!</td></tr>
<tr><td>
The multitude</td><td>Behold his mother! Behold his mother!</td></tr>
</table>
</BODY>
</HTML>
Rendered output is available at http://www.diga.me.uk/csvhtml.gif

Julia

<lang Julia>function csv2html(fname::ASCIIString; header::Bool=false)

   csv = readcsv(fname)
   @assert(length(csv) > 0)
   str = """

<html>

<head>

   <style type="text/css">
       body {
           margin: 2em;
       }
       h1 {
           text-align: center;
       }
       table {
           border-spacing: 0;
           box-shadow: 0 0 0.25em #888;
           margin: auto;
       }
       table,
       tr,
       th,
       td {
           border-collapse: collapse;
       }
       th {
           color: white;
           background-color: rgb(43, 53, 59);
       }
       th,
       td {
           padding: 0.5em;
       }
       table tr:nth-child(even) td {
           background-color: rgba(218, 224, 229, 0.850);
       }
   </style>

</head>

<body>

csv2html Example

""" tags = header ? ("") : ("")
   for i=1:size(csv, 2)
       str *= "            " * tags[1] * csv[1, i] * tags[2] * "\n"
   end
   
str *= " "^8 * "\n" for i=2:size(csv, 1) str *= " \n" for j=1:size(csv, 2) str *= " " * "\n"
       end
   
str *= " \n" end str * "
", "", "
" * csv[i, j] * "

\n</body>\n\n</html>\n"

end

print(csv2html("input.csv", header=true))</lang>

Output:

<lang html5><html>

<head>

   <style type="text/css">
       body {
           margin: 2em;
       }
       h1 {
           text-align: center;
       }
       table {
           border-spacing: 0;
           box-shadow: 0 0 0.25em #888;
           margin: auto;
       }
       table,
       tr,
       th,
       td {
           border-collapse: collapse;
       }
       th {
           color: white;
           background-color: rgb(43, 53, 59);
       }
       th,
       td {
           padding: 0.5em;
       }
       table tr:nth-child(even) td {
           background-color: rgba(218, 224, 229, 0.850);
       }
   </style>

</head>

<body>

csv2html Example

Character Speech
The multitude The messiah! Show us the messiah!
Brians mother Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!
The multitude Who are you?
Brians mother I'm his mother; that's who!
The multitude Behold his mother! Behold his mother!

</body>

</html></lang>

Lua

<lang lua>FS = "," -- field separator

csv = [[ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! ]]

csv = csv:gsub( "<", "<" ) csv = csv:gsub( ">", "&gr;" )

html = { "

" } for line in string.gmatch( csv, "(.-\n)" ) do str = "" for field in string.gmatch( line, "(.-)["..FS.."?\n?]" ) do str = str .. ""
   end
str = str .. "" html[#html+1] = str; end html[#html+1] = "
" .. field .. "

"

for _, line in pairs(html) do

   print(line)

end</lang>

<lang html5>

CharacterSpeech
The multitudeThe messiah! Show us the messiah!
Brians mother<angry&gr;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry&gr;
The multitudeWho are you
Brians motherI'm his mother; that's who!
The multitudeBehold his mother! Behold his mother!

</lang>

=={{header|M