Task: CSV data manipulation


C++: #include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <utility>
#include <functional>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>

class CSV
{
public:
    CSV(void) : m_nCols( 0 ), m_nRows( 0 )
    {}

    bool open( const char* filename, char delim = ',' )
    {
        std::ifstream file( filename );
    
        clear();
        if ( file.is_open() )
        {
            open( file, delim );
            return true;
        }

        return false;
    }

    void open( std::istream& istream, char delim = ',' )
    {
        std::string         line;

        clear();
        while ( std::getline( istream, line ) )
        {
            unsigned int nCol = 0;
            std::istringstream    lineStream(line);
            std::string           cell;

            while( std::getline( lineStream, cell, delim ) )
            {
                m_oData[std::make_pair( nCol, m_nRows )] = trim( cell );
                nCol++;
            }
            m_nCols = std::max( m_nCols, nCol );
            m_nRows++;
        }
    }

    bool save( const char* pFile, char delim = ',' )
    {
        std::ofstream ofile( pFile );
        if ( ofile.is_open() )
        {
            save( ofile );
            return true;
        }
        return false;
    }

    void save( std::ostream& ostream, char delim = ',' )
    {
        for ( unsigned int nRow = 0; nRow < m_nRows; nRow++ )
        {
            for ( unsigned int nCol = 0; nCol < m_nCols; nCol++ )
            {
                ostream << trim( m_oData[std::make_pair( nCol, nRow )] );
                if ( (nCol+1) < m_nCols )
                {
                    ostream << delim;
                }
                else
                {
                    ostream << std::endl;
                }
            }
        }
    }

    void clear()
    {
        m_oData.clear();
        m_nRows = m_nCols = 0;
    }

    std::string& operator()( unsigned int nCol, unsigned int nRow )
    {
        m_nCols = std::max( m_nCols, nCol+1 );
        m_nRows = std::max( m_nRows, nRow+1 );
        return m_oData[std::make_pair(nCol, nRow)];
    }

    inline unsigned int GetRows() { return m_nRows; }
    inline unsigned int GetCols() { return m_nCols; }

private:
    
    inline std::string &trim(std::string &s) 
    {
        
        s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
        s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
        return s;
    }

private:
    std::map<std::pair<unsigned int, unsigned int>, std::string> m_oData;

    unsigned int    m_nCols;
    unsigned int    m_nRows;
};


int main()
{
    CSV oCSV;

    oCSV.open( "test_in.csv" );
    oCSV( 0, 0 ) = "Column0";
    oCSV( 1, 1 ) = "100";
    oCSV( 2, 2 ) = "200";
    oCSV( 3, 3 ) = "300";
    oCSV( 4, 4 ) = "400";
    oCSV.save( "test_out.csv" );
    return 0;
}









Fortran: program rowsum
    implicit none
    character(:), allocatable :: line, name, a(:)
    character(20) :: fmt
    double precision, allocatable :: v(:)
    integer :: n, nrow, ncol, i
    
    call get_command_argument(1, length=n)
    allocate(character(n) :: name)
    call get_command_argument(1, name)
    open(unit=10, file=name, action="read", form="formatted", access="stream")
    deallocate(name)
    
    call get_command_argument(2, length=n)
    allocate(character(n) :: name)
    call get_command_argument(2, name)
    open(unit=11, file=name, action="write", form="formatted", access="stream")
    deallocate(name)

    nrow = 0
    ncol = 0
    do while (readline(10, line))
        nrow = nrow + 1
        
        call split(line, a)
        
        if (nrow == 1) then
            ncol = size(a)
            write(11, "(A)", advance="no") line
            write(11, "(A)") ",Sum"
            allocate(v(ncol + 1))
            write(fmt, "('(',G0,'(G0,:,''',A,'''))')") ncol + 1, ","
        else
            if (size(a) /= ncol) then
                print "(A,' ',G0)", "Invalid number of values on row", nrow
                stop
            end if

            do i = 1, ncol
                read(a(i), *) v(i)
            end do
            v(ncol + 1) = sum(v(1:ncol))
            write(11, fmt) v
        end if
    end do
    close(10)
    close(11)
contains
    function readline(unit, line)
        use iso_fortran_env
        logical :: readline
        integer :: unit, ios, n
        character(:), allocatable :: line
        character(10) :: buffer
        
        line = ""
        readline = .false.
        do
            read(unit, "(A)", advance="no", size=n, iostat=ios) buffer
            if (ios == iostat_end) return
            readline = .true.
            line = line // buffer(1:n)
            if (ios == iostat_eor) return
        end do
    end function

    subroutine split(line, array, separator)
        character(*) line
        character(:), allocatable :: array(:)
        character, optional :: separator
        character :: sep
        integer :: n, m, p, i, k
        
        if (present(separator)) then
            sep = separator
        else
            sep = ","
        end if
        
        n = len(line)
        m = 0
        p = 1
        k = 1
        do i = 1, n
            if (line(i:i) == sep) then
                p = p + 1
                m = max(m, i - k)
                k = i + 1
            end if
        end do
        m = max(m, n - k + 1)
        
        if (allocated(array)) deallocate(array)
        allocate(character(m) :: array(p))

        p = 1
        k = 1
        do i = 1, n
            if (line(i:i) == sep) then
                array(p) = line(k:i-1)
                p = p + 1
                k = i + 1
            end if
        end do
        array(p) = line(k:n)
    end subroutine
end program