Parse a CSV row

Parse a CSV row according to the RFC 4180

by rplantiko

HTML

<h2>Other solutions out there?</h2>
Two possible functions to parse a CSV row as specified in <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>
<p>
<b>Single row:</b>
<p>
<textarea id="input" cols="80" rows="3"></textarea>
</p>
<p>
<button type="button" id="parse">Parse</button>
</p>
<pre id="log"></pre>

JavaScript

"use strict";

var log = document.getElementById("log")

document.getElementById("input").value = 
 `1,a,"a","""Hallo"",he said, ""howdy?""","",,"Hi, there","""Hi, there""
 ""Oh, that was a line break"""`

document.getElementById("parse").addEventListener("click", function() {

  var input = document.getElementById("input").value

  log.textContent = input + "\n\n"

  show( parseCSV1( input ) )
  show( parseCSV2( input ) )

})

function show(result) {
  log.insertAdjacentText("beforeend","\n")
  result.forEach((cell,i)=>
    log.insertAdjacentText("beforeend",`${i+1}: ${cell}\n`)
  )
}

// Version 1: Scan through the string with for..of
function parseCSV1(row,sep=',') {
  var result = []
  var quoteMode = false, s = "", c
  for (c of row) {
    quoteMode = quoteMode != (c == '"')
    if (!quoteMode && c == sep) {
      addToResult(s)
      s = ""
    } else
    s+=c
  }
  if (s || c == sep) addToResult(s)
  return result
  function addToResult(cell) {
    result.push( 
      cell.replace(/(?!^)""/g,'"')
          .replace(/^"([\s\S]*)"$/,"$1")
      )
  }
}

// Version 2: use Array function 'reduce()'
function parseCSV2(row,sep=',') {
  var len = row.length, 
      quoteMode = false, 
      prev = 0
  return (row+" ").split('').reduce(function(result,c,i) {
    quoteMode = quoteMode != (c == '"')
    if (!quoteMode && c == sep || i == len) {
      result.push(
        row.substring(prev,i)
           .replace(/(?!^)""/g,'"')
           .replace(/^"([\s\S]*)"$/,"$1")
       )
       prev = i+1    
    }  
    return result
  },[])
}