Software Archive
Read-only legacy content
17061 Discussions

How to ignore tabs

waynebruce
Beginner
1,979 Views
I am reading in input files from a text file. Sometimes the inputs would contain tabs. How do I either ignore the tabs, or recognize them as spaces instead? I am just doing a regular READ statement, but somehow the tabs seems to screw up the READ statement. Fortran doesn't seem to skip over the tabs to the next data point, but instead reads in the tab AS a data point, thus screwing up the rest of the table.

thanks.
0 Kudos
6 Replies
Intel_C_Intel
Employee
1,979 Views
You have my sympathy! I once received a data file that had been incompetently passed through a spreadsheet, with the result that it finished up with tabs inside the first number, splitting it into two.

I have always maintained that Fortran should include a Left-justifying function that removes not just leading spaces (as ADJUSTL does), but all leading non-printing characters - which would include tabs. Similarly an addition to TRIM & LEN_TRIM, for trailing, non-printing characters.

I use a function LENGTH that gives the length without trailing, non-printing characters, and a Subroutine JUSTIFY_L that removes leading spaces and tabs. After reading the discussion on "Assumed-length character functions" (which now should be near the top of the pile because I have just posted a reply), I am about to turn JUSTIFY_L into a function. If you are interested, I will post it on this message.

In the mean time it might help you if you first read in each data line as a character string and then search from the start for the first character that is not a space or tab, then read in the next value from there.

Bear of little brain
0 Kudos
Steven_L_Intel1
Employee
1,979 Views
CVF numeric formatted input treats a tab as if it were a blank. However, a problem can appear if you are using formatted input with specific columns, and the user entered a tab to move to "the next tab stop". Fortran doesn't know about tab stops - a tab is just a single character.

Consider using list-directed input (FMT=*), which is much more forgiving.

Steve
0 Kudos
Intel_C_Intel
Employee
1,979 Views
I am sure that Steve has the correct analysis here, but FWIW I have written a function JUSTIFYL that removes leading spaces and tabs and replaces them with trailing spaces. The length of the string is unchanged, which simplifies the programming. It has not been tested very much, having only just been written, so would anyone brave (or foolhardy) enough to use it please flag up any problems.

C File justifyl.f
MODULE STRINGFNS
CONTAINS
C
FUNCTION JUSTIFYL(STRING)
IMPLICIT NONE
CHARACTER(LEN = *), INTENT(IN) :: STRING
CHARACTER(LEN = LEN(STRING)) JUSTIFYL
INTEGER I, L
L=LEN(STRING)
JUSTIFYL = REPEAT(' ',L) ! Clear out any rubbish (try leaving this out)
I=1
DO WHILE ((STRING(I:I) == ' ' .OR. STRING(I:I) == CHAR(9))
1 .AND. I < L) ! Look for first non-(space or tab) character
I=I+1
END DO
JUSTIFYL(1:L-I+1) = STRING(I:L) ! Shift left
JUSTIFYL(L-I+2:L) = REPEAT(' ',I-1) ! Replace end with spaces
END FUNCTION JUSTIFYL
END MODULE STRINGFNS
C
PROGRAM LJUSTIFY
USE STRINGFNS
IMPLICIT NONE
CHARACTER*30 INSTRING
CHARACTER*1, PARAMETER :: TAB = CHAR(9)
INSTRING = ' '//TAB//' '//TAB//'Test Justifyl'
WRITE(*,'(A)') '#'//INSTRING//'#'
WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#'
INSTRING = ' Z'
WRITE(*,'(A)') '#'//INSTRING//'#'
WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#'
INSTRING = TAB//'Z'
WRITE(*,'(A)') '#'//INSTRING//'#'
WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#'
INSTRING = ''
WRITE(*,'(A)') '#'//INSTRING//'#'
WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#'
PAUSE
END PROGRAM ljustify
C END OF FILE justifyl.f

Output looks like this, depending on tab settings
# Test Justifyl #
#Test Justifyl #
# Z #
#Z #
# Z #
#Z #
# #
# #

Bear of little brain
0 Kudos
Intel_C_Intel
Employee
1,979 Views
Apologies for that - I had hoped that the magic instructions were no longer necessary after the change of the appearance of the forum. I'll try again.
 
C    File justifyl.f 
      MODULE STRINGFNS 
      CONTAINS 
C 
      FUNCTION JUSTIFYL(STRING) 
      IMPLICIT NONE 
      CHARACTER(LEN = *), INTENT(IN) :: STRING 
      CHARACTER(LEN = LEN(STRING)) JUSTIFYL 
      INTEGER I, L 
      L=LEN(STRING) 
      JUSTIFYL = REPEAT(' ',L) ! Clear out any rubbish (try leaving this out) 
      I=1 
      DO WHILE ((STRING(I:I) == ' ' .OR. STRING(I:I) == CHAR(9)) 
     1          .AND. I < L)              ! Look for first non-(space or tab) character 
        I=I+1 
      END DO 
      JUSTIFYL(1:L-I+1) = STRING(I:L)       ! Shift left 
      JUSTIFYL(L-I+2:L) = REPEAT(' ',I-1)   ! Replace end with spaces 
      END FUNCTION JUSTIFYL 
      END MODULE STRINGFNS 
C 
      PROGRAM LJUSTIFY 
      USE STRINGFNS 
      IMPLICIT NONE 
      CHARACTER*30 INSTRING 
      CHARACTER*1, PARAMETER :: TAB = CHAR(9) 
      INSTRING = '   '//TAB//'    '//TAB//'Test Justifyl' 
      WRITE(*,'(A)') '#'//INSTRING//'#' 
      WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#' 
      INSTRING = ' Z' 
      WRITE(*,'(A)') '#'//INSTRING//'#' 
      WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#' 
      INSTRING = TAB//'Z' 
      WRITE(*,'(A)') '#'//INSTRING//'#' 
      WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#' 
      INSTRING = '' 
      WRITE(*,'(A)') '#'//INSTRING//'#' 
      WRITE(*,'(A)') '#'//JUSTIFYL(INSTRING)//'#' 
      PAUSE 
      END PROGRAM ljustify 
C    END OF FILE justifyl.f 
 
Output looks like this, depending on tab settings 
#         Test Justifyl        # 
#Test Justifyl           # 
# Z                           # 
#Z                            # 
#     Z                              # 
#Z                            # 
#                              # 
#                              # 


Bear of little brain
0 Kudos
Intel_C_Intel
Employee
1,979 Views
I'm not quite sure what you're trying to achieve here. If you want to eliminate any leading block of tabs and spaces, you could simplify your function body a bit with:
 
      i = verify(string, achar(20)//achar(9)) 
      if(i == 0) then 
         justifyl = ' ' 
      else 
         justifyl = string(i:) 
      end if 

If you want to turn all tabs to spaces, you could cast the string into a character array and use array intrinsics:
 
      character temp(len(string)) 
 
      temp = transfer(string, temp) 
      temp = merge(temp, ' ',  temp /= achar(9)) 
      justifyl = transfer(temp, justifyl) 
! And now perhaps 
      justifyl = adjustl(justifyl) 

Or if you wanted to squeeze out all the tabs,
 
      character temp(len(string)) 
 
      temp = transfer(string, temp) 
      temp = pack(temp,  temp /= achar(9), spread(' ', 1, len(string))) 
      justifyl = transfer(temp, justifyl) 
! And now perhaps 
      justifyl = adjustl(justifyl) 

None of the above seem entirely inconsistent with your description of the problem. You may wan to look up the topics "Character assignment statements" and "Character functions, categories of" in the online docs.
0 Kudos
Intel_C_Intel
Employee
1,979 Views
Among other possible errors in my untested code above, achar(20) should be changed to achar(32) -- I always think about ASCII codes in hex.
0 Kudos
Reply