Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28520 Discussions

How do I detect the length of an input line?

WSinc
New Contributor I
1,714 Views

When I am reading in a text file, say as follows:

read(5,100)line

100 format(A)

How can I tell how many characters were in the line I read in?

It blanks out the unread characters, so that obscures the actual length of

the input line. Otherwise I could set all the characters to "$" and see which ones

were not overridden when I read in the next line.

0 Kudos
8 Replies
WSinc
New Contributor I
1,714 Views

BTW, as far as I can tell, it does not encode CRs or Line feeds, using that format.

So is there another way to read in the text to get that information?

0 Kudos
TimP
Honored Contributor III
1,714 Views

Anything wrong with len_trim for your usage?

Please, there are many good references on Fortran, both published and on-line, which you might have taken the time to consult in your vaunted 40 years of experience.

0 Kudos
IanH
Honored Contributor II
1,714 Views

Use non-advancing input along with the SIZE and IOSTAT specifiers.

[fortran]! Short line.
! A longer line - one that is longer than our buffer.
! This complete line is read into the_complete_line variable even though it is really really long.
PROGRAM GetLengthOfStringRead
  USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: IOSTAT_END
  IMPLICIT NONE
 
  CHARACTER(20) :: buffer
  INTEGER :: stat
  INTEGER :: sz
  INTEGER :: unit
  CHARACTER(:), ALLOCATABLE :: the_complete_line
 
  CHARACTER(*), PARAMETER :: filename  &
      = '2013-10-22 GetLengthOfStringRead.f90'
 
  OPEN( NEWUNIT=unit, FILE=filename,  &
      ACTION='READ', STATUS='OLD' )
 
  ! Get a short line
  READ(unit, "(A)", ADVANCE='NO', IOSTAT=stat, SIZE=sz) buffer
  PRINT "('stat was ',I0,', SIZE was ',I0,' and buffer was ""',A,'""')",  &
      stat, sz, buffer
  ! If we didn't hit the end of the record, then move to the next record.
  IF (stat == 0) READ (unit, "()")
 
  ! Get a long line.
  READ(unit, "(A)", ADVANCE='NO', IOSTAT=stat, SIZE=sz) buffer
  PRINT "('stat was ',I0,', SIZE was ',I0,' and buffer was ""',A,'""')",  &
      stat, sz, buffer
  ! If we didn't hit the end of the record, then move to the next record.
  IF (stat == 0) READ (unit, "()")
 
  ! Get the complete line.
  the_complete_line = ''
  DO
    READ (unit, "(A)", ADVANCE='NO', IOSTAT=stat, SIZE=sz) buffer
    PRINT "('stat was ',I0,', SIZE was ',I0,' and buffer was ""',A,'""')",  &
      stat, sz, buffer
    IF (stat > 0) STOP 'Oops!'    ! Some sort of error.
    IF (stat == IOSTAT_END) STOP 'End of file!'
    the_complete_line = the_complete_line // buffer(:sz)
    IF (stat < 0) EXIT    ! End of record.
  END DO
 
  PRINT "('The complete line was ""',A,'""')", the_complete_line
 
  CLOSE(unit)
END PROGRAM GetLengthOfStringRead

[/fortran]

If you are using formatted stream access and you have an incomplete record at the end of a file the line reading thing might miss the data in that incomplete record, but I'm not sure how things are supposed to work in that case.  The above seems to fit the behaviour of the compilers that I've played with recently.

0 Kudos
John_Campbell
New Contributor II
1,714 Views

Bill,

I'm not sure what problems you have with your code example:

read (5,100) line
100 format (A)
nc = len_trim (line)
mc = len (line)
nx = 0 ; do i = 1, len_trim(line) ; if (line(i:i) /= ' ') nx = nx+1 ; end do

I've appended the following statistics, which might explain your problem:
"mc" is the length of the character string: line, so that if the information being read is longer than MC then the extra information will be lost. If this is your problem, the solution is to either use stream input or make "line" very big.
"nc" will be the position of the last non-blank character of line read. If the problem is you want to count training blanks (which is a problem for fortran input), again you have to go to stream input.
"nx" is the count of non-blank characters read into line.

If you want to know the length of the line, then adapting Ian's code to get the length of the next line could be useful. If you want to do a single pass read, then you need to allocate LINE to be bigger than needed.

Perhaps a routine that returns the maximum line length and the number of lines for a given file name would be a useful utility routine.

John

0 Kudos
WSinc
New Contributor I
1,714 Views

Thanks for your suggestions -

Someone was being sarcastic about my experience, but I only did science/engineering code and that was with "ancient" versions of Fortran.

Anyway, the text being read in was a .TXT file with embedded line feeds and carriage returns. But testing for blanks would not solve the

problem, since english text has blanks between words as well.The text I refer to is something you would see in an E-mail, or an article in a book or on a Web site.

I will try some experimentation with your different suggestions, since this is a problem

I have never encountered before.

One curious thing - my E-mail showed over 40 replies but only two of you responded.

0 Kudos
WSinc
New Contributor I
1,714 Views

Someone mentioned (not in this forum) using STREAM input, but I don't see anything about that here.

Is that a particular type of file, or does that refer to any kind of file ?

The Fortran help was really pitiful about this topic.

0 Kudos
Steven_L_Intel1
Employee
1,714 Views

If you don't mind using an extension, you can do this:

READ (5,100) linelen, line
100 FORMAT (Q,A)

The Q format, on input, transfers to the next I/O list item the number of characters remaining in the current line.

I don't think stream I/O would make this much easier for you.  You could read a character at a time and use the EOR= indication to see when you reached the end of a record.

0 Kudos
John_Campbell
New Contributor II
1,714 Views

Bill,

You should be able to open the file for transparent access and read one character at a time. ( make this a function get_next_character () )
You can then build on this and test for <CR>=13 or <LF>=10 or other control characters (0:31) and then assemble lines of text and note the number of characters in each line. You can differentiate between DOS (CR + LF), Unix formats or others.

The following is an example from another compiler. (I can't see an example of transparent access in the ifort documentation.)

[fortran]!  Open the text file as transparent
!
      file_name = get_file_name ()
!
      open (unit  =11,               &
            file  =file_name,        &
            status='OLD',            &
            form  ='UNFORMATTED',    &
            access='TRANSPARENT',    &
            iostat=iostat)
      write (*,2000) 'Opening file ',trim(file_name),' iostat = ',iostat
2000  format (a,a,a,i0)
!
!  Read all characters
!
      count_ic = 0
      n        = 0
      nl       = 0
      nc       = 0
      na       = 0
      nz       = 0
!
      do
         read (unit=11, iostat=iostat) c
         if (iostat /= 0) exit
!
         n  = n + one
         ic = ichar(c)
         count_ic(ic) = count_ic(ic)+one
         select case (ic)
            case (10,13)
               nl = nl + one   ! line control characters ; 10:LF indicates end of line
            case (0:9,11,12,14:31)
               nc = nc + one   ! control characters
            case (32:126)
               na = na + one   ! normal character
            case (127:256)
               nz = nz + one   ! other character
            case default
               write (*,*) 'Unrecognised character : ichar =',ic
         end select
      end do
[/fortran]

Once you see the types of control characters in the file, you can build on this and start assembling and reporting lines and line length.

John

0 Kudos
Reply