parse_csv_line Subroutine

private subroutine parse_csv_line(line, fields)

Parse a CSV line into fields

Helper subroutine that splits a CSV line into individual fields, handling quoted strings and commas within quotes.

@param[in] line The CSV line to parse @param[out] fields Array of parsed field values

Note

Supports quoted fields with embedded commas

Note

Maximum 50 fields per line

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: line
character(len=100), intent(out), allocatable :: fields(:)

Source Code

    subroutine parse_csv_line(line, fields)
        character(len=*), intent(in) :: line
        character(len=100), allocatable, intent(out) :: fields(:)

        integer :: i, start, field_count, len_line
        logical :: in_quotes, is_delimiter
        character(len=100) :: temp_fields(50)  ! Max 50 fields
        character(len=:), allocatable :: trimmed_line

        trimmed_line = trim(line)
        len_line = len(trimmed_line)

        if (len_line == 0) then
            allocate (fields(0))
            return
        end if

        field_count = 0
        start = 1
        in_quotes = .false.

        do i = 1, len_line + 1
            is_delimiter = .false.

            ! Check for quotes within bounds
            if (i <= len_line) then
                if (trimmed_line(i:i) == '"') then
                    in_quotes = .not. in_quotes
                    cycle
                end if

                ! Check if current character is a delimiter
                if (trimmed_line(i:i) == ',' .and. .not. in_quotes) then
                    is_delimiter = .true.
                end if
            end if

            ! Process field if we hit a delimiter or end of line
            if (i > len_line .or. is_delimiter) then
                field_count = field_count + 1
                if (field_count > 50) error stop "Too many fields in CSV line"

                ! Extract the field
                if (i == start .or. start > len_line) then
                    temp_fields(field_count) = ""
                else
                    if (i > len_line) then
                        temp_fields(field_count) = trim(adjustl(trimmed_line(start:len_line)))
                    else
                        temp_fields(field_count) = trim(adjustl(trimmed_line(start:i - 1)))
                    end if

                    ! Remove surrounding quotes if present
                    if (len(trim(temp_fields(field_count))) >= 2) then
                        if (temp_fields(field_count) (1:1) == '"' .and. &
         temp_fields(field_count) (len(trim(temp_fields(field_count))):len(trim(temp_fields(field_count)))) == '"') then
                         temp_fields(field_count) = temp_fields(field_count) (2:len(trim(temp_fields(field_count))) - 1)
                        end if
                    end if
                end if
                start = i + 1
            end if
        end do

        allocate (fields(field_count))
        fields = temp_fields(1:field_count)
    end subroutine parse_csv_line