R error handling using read.table and defined colClasses having corrupt lines in CSV file
<p>I have a big .csv file to read in. Badly some lines are corrupt, meaning that something is wrong in the formatting like a number like <code>0.-02</code> instead of <code>-0.02</code>. Sometimes even the line break (<code>\n</code>) is missing, so that two lines merge to one.</p>

<p>I want to read the .csv file with <code>read.table</code> and define all <code>colClasses</code> to the format that I expect the file to have (except of course for the corrupt lines). This is a minimal example:</p>

<pre><code>colNames &lt;- c("date", "parA", "parB")
colClasses &lt;- c("character", "numeric", "numeric")

inputText &lt;- "2015-01-01;123;-0.01\n
              2015-01-02;421;-0.022015-01-03;433;-0.04\n
              2015-01-04;321;-0.03\n
              2015-01-05;230;-0.05\n
              2015-01-06;313;0.-02"

con &lt;- textConnection(inputText, "r")

mydata &lt;- read.table(con, sep=";", fill = T, colClasses = colClasses)
</code></pre>

<p>At the first corrupt lines <code>read.table</code> stops with the error:</p>

<pre><code>Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings,  : 
  scan() expected 'a real', got '-0.022015-01-03'
</code></pre>

<p>With this error message I have no Idea in which line of the input the error occurred. Hence my only option is to copy the line <code>-0.022015-01-03</code> and search for it in the file. But this is really annoying if you have to do it for a lot of lines and always have to re-execute <code>read.table</code> until it detects the next corrupt line.</p>

<p>So my question is:</p>

<ol>
<li>Is there a way to get <code>read.table</code> to tell me the line where the error occurred (and maybe save it for further processing)</li>
<li>Is there a way to get <code>read.table</code> to just skip lines with improper formatting (not to stop at an error)?</li>
<li>Did anyone figure out a way to display these lines for manual correction during the read process? I mean maybe display the whole corrupt line in the plain csv format for manual correction (maybe including the line before and after) and then continue the read-in process including the corrected lines.</li>
</ol>

<p>What I tried so far is to read everything with <code>colClasses="character"</code> to avoid format checking in the first place. Then do the format checking while I convert every column to the right format. Then <code>which()</code> all lines where the format could not be converted or the result is <code>NA</code> and just delete them.</p>

<hr>

<h1>I have a solution, but it its very slow</h1>

<p>With ideas I got from some of the comments the thing I tried next is to read the input line by line with <code>readLine</code> and pipe the result to <code>read.table</code> via the <code>text</code> argument. If <code>read.table</code> files the line is presented to the user via <code>edit()</code> for correction and re-submission. Here is my code:</p>

<pre><code>con &lt;- textConnection(inputText, "r")
mydata &lt;- data.frame()
while(length(text &lt;- readLines(con, n=1)) &gt; 0){

    correction = T
    while(correction) {

        err &lt;- tryCatch(part &lt;- read.table(text=text, sep=";", fill = T, 
                                            col.names = colNames, 
                                            colClasses = colClasses),
                        error=function(e) e)

        if(inherits(err, "error")){

            # try to correct this line
            message(err, "\n")
            text &lt;- edit(text)

        }else{

            correction = F

        }
    }

    mydata &lt;- rbind(mydata, part)

}
</code></pre>

<p>If the user made the corrections right this returns:</p>

<pre><code>&gt; mydata
        date parA  parB
1 2015-01-01  123 -0.01
2 2015-01-02  421 -0.02
3 2015-01-03  433 -0.04
4 2015-01-04  321 -0.03
5 2015-01-05  230 -0.05
6 2015-01-06  313 -0.02
</code></pre>

<p>The input text had 5 lines, since one linefeed was missing. The corrected output has 6 lines and the <code>0.-02</code> is corrected to <code>-0.02</code>.</p>

<p>What I still would change in this solution is to present all corrupt lines together for correction after everything is read in. This way the user can run the script and after it finished can do all corrections at once. But for a minimal example this should be enough.</p>

<p>The really bad thing about this solution is, that it is <strong>really slow</strong>! Too slow to handle big datasets. Hence I still would like to have another solution using more standard methods or probably a special package.</p>