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
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
character(len=*), | intent(in) | :: | line | |||
character(len=100), | intent(out), | allocatable | :: | fields(:) |
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