-
Notifications
You must be signed in to change notification settings - Fork 184
Add character array interface to loadtxt #919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,36 +6,37 @@ title: io | |||||
|
||||||
[TOC] | ||||||
|
||||||
## `loadtxt` - load a 2D array from a text file | ||||||
## `loadtxt` - load a 2D array or 1D character array from a text file | ||||||
|
||||||
### Status | ||||||
|
||||||
Experimental | ||||||
|
||||||
### Description | ||||||
Loads a rank-2 `array` from a text file. | ||||||
Loads a rank-2 `array` or rank-1 `character array` from a text file. | ||||||
|
||||||
### Syntax | ||||||
|
||||||
`call ` [[stdlib_io(module):loadtxt(interface)]] `(filename, array [, skiprows] [, max_rows] [, fmt])` | ||||||
`call ` [[stdlib_io(module):loadtxt(interface)]] `(filename, array [, skiprows] [, max_rows] [, fmt], [,skip_blank_lines])` | ||||||
|
||||||
### Arguments | ||||||
|
||||||
`filename`: Shall be a character expression containing the file name from which to load the rank-2 `array`. | ||||||
|
||||||
`array`: Shall be an allocatable rank-2 array of type `real`, `complex` or `integer`. | ||||||
`array`: Shall be an allocatable rank-2 array of type `real`, `complex` or `integer` or a allocatable rank-1 `character` array. | ||||||
|
||||||
`skiprows` (optional): Skip the first `skiprows` lines. If skipping more rows than present, a 0-sized array will be returned. The default is 0. | ||||||
|
||||||
`max_rows` (optional): Read `max_rows` lines of content after `skiprows` lines. A negative value results in reading all lines. A value of zero results in no lines to be read. The default value is -1. | ||||||
|
||||||
`fmt` (optional): Fortran format specifier for the text read. Defaults to the write format for the data type. Setting fmt='*' will specify list directed read. | ||||||
`fmt` (optional): Fortran format specifier for the text read. Defaults to the write format for the data type. Setting fmt='*' will specify list directed read. Valid only for `real`, `complex` and `integer`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
`skip_blank_lines` (optional): Will ignore blank lines in the text file. Valid only for `character` array. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
|
||||||
### Return value | ||||||
|
||||||
Returns an allocated rank-2 `array` with the content of `filename`. | ||||||
Returns an allocated rank-2 `array` with the content of `filename`, or a rank-1 `character` array where the length is the longest line of the file. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
### Example | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -66,6 +66,7 @@ module stdlib_io | |||||
#:for k1, t1 in KINDS_TYPES | ||||||
module procedure loadtxt_${t1[0]}$${k1}$ | ||||||
#:endfor | ||||||
module procedure :: loadtxt_char | ||||||
end interface loadtxt | ||||||
|
||||||
interface savetxt | ||||||
|
@@ -192,6 +193,119 @@ contains | |||||
end subroutine loadtxt_${t1[0]}$${k1}$ | ||||||
#:endfor | ||||||
|
||||||
subroutine loadtxt_char(filename, d, skiprows, max_rows, skip_blank_lines) | ||||||
!! | ||||||
!! Loads a text file into a 1D character array. | ||||||
!! | ||||||
character(len=*), intent(in) :: filename | ||||||
character(len=:), intent(out), allocatable :: d(:) | ||||||
integer, intent(in), optional :: skiprows, max_rows | ||||||
logical, intent(in), optional :: skip_blank_lines | ||||||
|
||||||
logical :: skip_blank_lines_, read_line | ||||||
|
||||||
integer :: i, u, len_text, max_line_length, line_length, start_pos, end_pos, & | ||||||
current_line, next_line_pos, step, max_rows_, skiprows_ | ||||||
|
||||||
character(len=:), allocatable :: text | ||||||
|
||||||
! Set default optional values | ||||||
skiprows_ = optval(skiprows, 0) | ||||||
max_rows_ = optval(max_rows, -1) | ||||||
skip_blank_lines_ = optval(skip_blank_lines, .false.) | ||||||
|
||||||
!! Open and store all of file contents. | ||||||
open (newunit=u, file=filename, action='read', form='unformatted', access='stream') | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this use the new |
||||||
inquire(unit=u, size=len_text) ! Get total character count of file. | ||||||
allocate(character(len=len_text) :: text) | ||||||
read(u) text | ||||||
close(u) | ||||||
|
||||||
! Loop through file twice. | ||||||
! step = 1 loop will get line count, max line size and allocate character array. | ||||||
! step = 2 will fill the array. | ||||||
do step = 1, 2 | ||||||
max_line_length = 0 | ||||||
! Will skip skiprow lines if specified, since will only read line if current_line is positive. | ||||||
current_line = -skiprows_ | ||||||
next_line_pos = 1 | ||||||
do while (next_line_pos > 0) | ||||||
|
||||||
start_pos = next_line_pos | ||||||
|
||||||
! Search text starting at start_pos for end of line. end_pos will exclude CRLR or LR characters. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
! next line idx is the start of the next line. Will be 0 if last line in text. | ||||||
call get_line(text, start_pos, end_pos, next_line_pos) | ||||||
|
||||||
! Check for and skip blank lines if requested. | ||||||
read_line = .true. | ||||||
if (skip_blank_lines_) then | ||||||
if (len_trim(text(start_pos:end_pos)) == 0) read_line = .false. | ||||||
endif | ||||||
|
||||||
if (read_line) then | ||||||
current_line = current_line + 1 | ||||||
if (step == 1) then | ||||||
line_length = end_pos - start_pos + 1 | ||||||
if ((line_length > max_line_length) .and. (current_line > 0)) max_line_length = line_length | ||||||
else | ||||||
if (current_line > 0) d(current_line) = text(start_pos:end_pos) | ||||||
endif | ||||||
endif | ||||||
|
||||||
if ((max_rows_ >= 0) .and. (current_line == max_rows_)) exit ! Check max_row input if user has specified that. | ||||||
enddo | ||||||
|
||||||
if (step == 1) then | ||||||
! Allocate character array with max line size and line count. | ||||||
! If skip rows higher than lines found, allocate to size 0 array. | ||||||
allocate( character(max_line_length) :: d(max(0,current_line))) | ||||||
endif | ||||||
enddo | ||||||
|
||||||
contains | ||||||
|
||||||
pure subroutine get_line(text, start_idx, end_idx, next_line_idx) | ||||||
! Search ftext for line returns. Start_idx:end_idx will be the character variables of the line. | ||||||
! next_line_idx is the start of the next line. Will be 0 if last line in text. | ||||||
character(len=*), intent(in) :: text | ||||||
integer, intent(in) :: start_idx | ||||||
integer, intent(out) :: end_idx, next_line_idx | ||||||
|
||||||
integer :: idx, ascii_idx | ||||||
|
||||||
idx = start_idx | ||||||
|
||||||
!If no line ending found, will return end pos of text and next_line_idx = 0. | ||||||
next_line_idx = 0 | ||||||
end_idx = len(text) | ||||||
|
||||||
do while (idx <= len(text)) | ||||||
!! Find line end | ||||||
! Look for either CR or LR | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
ascii_idx = iachar(text(idx:idx)) | ||||||
|
||||||
if (ascii_idx == 13) then | ||||||
! Found CR return. Check for LR | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if (iachar(text(idx+1:idx+1)) == 10) then | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 questions:
Suggested change
|
||||||
end_idx = idx - 1 | ||||||
next_line_idx = idx + 2 | ||||||
return | ||||||
endif | ||||||
|
||||||
! Check for standalone LR | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
elseif (ascii_idx == 10) then | ||||||
end_idx = idx - 1 | ||||||
next_line_idx = idx + 1 | ||||||
return | ||||||
endif | ||||||
|
||||||
! Go to next line | ||||||
idx = idx + 1 | ||||||
enddo | ||||||
end subroutine get_line | ||||||
end subroutine loadtxt_char | ||||||
|
||||||
|
||||||
#:for k1, t1 in KINDS_TYPES | ||||||
subroutine savetxt_${t1[0]}$${k1}$(filename, d) | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.