Silverfrost Forums

Welcome to our forums

Problem reading last character

24 Jun 2009 9:03 #4719

This simple program will not read the last character of the string. The second output line generates a blank.

PROGRAM p
  IMPLICIT NONE
  CHARACTER(LEN=26) :: c1
  CHARACTER(LEN= 1) :: c2
!
  c1='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  READ (UNIT=c1(26:),FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(26:)
  WRITE (UNIT=*,FMT=*) c2
  READ (UNIT=c1(25:),FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(25:)
  WRITE (UNIT=*,FMT=*) c2
END PROGRAM p
24 Jun 2009 10:44 #4720

Simon, you are trying to read a single character with a * format, and that can't pick up the quote marks. Here's an effort to get them in place.

Eddie

PROGRAM p 
  IMPLICIT NONE 
  CHARACTER(LEN=26) :: c1 
  CHARACTER(LEN= 3) :: c2 
! 
  c1='ABCDEFGHIJKLMNOPQRSTUVWXYZ' 
  READ (UNIT=c1(1:1)//c1(26:),FMT=*) c2 
  WRITE (UNIT=*,FMT=*) c1(26:) 
  WRITE (UNIT=*,FMT=*) c2 
  READ (UNIT=c1(25:),FMT=*) c2 
  WRITE (UNIT=*,FMT=*) c1(25:) 
  WRITE (UNIT=*,FMT=*) c2 
END PROGRAM p
24 Jun 2009 6:01 (Edited: 6 Jul 2009 12:28) #4721

Thanks for the reply Eddie. I get 'A ' as the second output so the Z is still missing. Perhaps I should give a little bit more background to indicate why this problem arises.

Let me change the program to the following:

PROGRAM p
  IMPLICIT NONE
  CHARACTER(LEN=26) :: c1
  CHARACTER(LEN= 3) :: c2
!
  c1='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  READ (UNIT=c1(26:),FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(26:)
  WRITE (UNIT=*,FMT=*) c2
  READ (UNIT=c1(25:),FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(25:)
  WRITE (UNIT=*,FMT=*) c2
END PROGRAM p

The only difference from the original is that c2 is length 3 instead of 1. c1 typically is a line containing a string of information marked by tags. For example, c1 may look like the following:

'NAME=Simon, SEX=M, OCCUPATION=scientist'

I search for the keywords written in bold and then read the corresponding values. The keywords are not necessarily always present, and can be in any order, and the length of the value string is not fixed (for example, SEX could be 'Male' or 'M').

In the example above, I can read all the values OK, but if the order is reversed:

'NAME=Simon, OCCUPATION=scientist, SEX=M'

then I may fail to read M if there are no trailing blanks.

I have to use READ with FMT=* rather than FMT='(A)' because otherwise when the values are in the original order I would read past the comma separators, and would then have to check to delete any extraneous text.

It is not too difficult to think of work-arounds, but it seems circuitous to have to be checking whether one is left trying to read only the last character.

25 Jun 2009 3:43 #4722

I'd go back to (A) or not use read statements at all.

Alteranatively why not parse the line testing for ',' and '=', keeping track of each couple and where the ,name and =value start.

PROGRAM p 
  IMPLICIT NONE 
  CHARACTER(LEN=26) :: c1 
  CHARACTER(LEN= 1) :: c2 
! 
  c1='ABCDEFGHIJKLMNOPQRSTUVWXYZ' 
!
! this works with (a)
  READ (UNIT=c1(26:),FMT=11) c2 
  WRITE (UNIT=*,FMT=11) c1(26:) 
  WRITE (UNIT=*,FMT=11) c2 
!
  READ (UNIT=c1(25:),FMT=11) c2 
  WRITE (UNIT=*,FMT=11) c1(25:) 
  WRITE (UNIT=*,FMT=11) c2 
11 format (a)
!
! or better still, use
  c2 = c1(26:) 
  WRITE (UNIT=*,FMT=*) c1(26:) 
  WRITE (UNIT=*,FMT=*) c2 
!
  c2 = c1(25:) 
  WRITE (UNIT=*,FMT=*) c1(25:) 
  WRITE (UNIT=*,FMT=*) c2 
!

END PROGRAM p
25 Jun 2009 5:01 #4724

Simon,

I only did the first one, and without too much care!

Isn't this a good example of where one might consider using NAMELIST? I'm not a big fan of NAMELIST, but if your data is in the form you indicate, NAMELIST takes care of all the decyphering. Presumably each line has the same format because each line is generated by some other software.

If the data is generated by humans (and the keywords may be missing or mispelled) then you are in a whole different, and potentially more complex, ballgame.

NAMELIST is definitely a standard feature in later marks of Fortran, and is fully supported in FTN95.

Eddie

3 Jul 2009 9:55 #4746

I found a simple solution to this problem: when reading the string, simply append a blank space to the end, as follows:

PROGRAM p
  IMPLICIT NONE
  CHARACTER(LEN=26) :: c1
  CHARACTER(LEN= 3) :: c2
!
  c1='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  READ (UNIT=c1(26:)//' ',FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(26:)
  WRITE (UNIT=*,FMT=*) c2
  READ (UNIT=c1(25:)//' ',FMT=*) c2
  WRITE (UNIT=*,FMT=*) c1(25:)
  WRITE (UNIT=*,FMT=*) c2
END PROGRAM p
3 Jul 2009 12:03 #4747

Simon,

If you want a simple solution, why use a read at all ?

Doesn't ' c2 = c1(26:) ' do the same thing ?

John

6 Jul 2009 12:23 #4756

John,

Certainly, but only if one knew a priori that there were no trailing characters. The problem I originally raised only occurred because I was being too lazy to check whether I was at or near the end of the string. I could easily have included a LEN_TRIM somewhere, and checked how many characters were left, but that seemed a bit pedantic. Having the trailing blank seems to have solved all the problems in my specific context, for now. Eddie's suggestion about NAMELIST was a good one, and would work in over 90% of my cases, but there are occasional fields generated or modified by hand that I'm having to account for.

Simon

6 Jul 2009 12:33 #4759

Simon,

I would expect that the problem relates to the interpretation of fmt=* If you used fmt='(a)' the result may have been different. I have written my free format interpreter without the use of formatted read. It is an easy solution.

The effective use of NAMELIST is something I have never managed to learn.

John

Please login to reply.