string manipulation in FORTRAN: strange behavior - fortran

If the input of the following working example ist - for example - "ach_40", the output is "ach_40.DOC?" and "ach_40.IMG". Where is the "?" coming from?
The code is:
program test
character*8 filin
character*12 dummy,file1,file2
character*4 :: img = '.IMG', doc='.DOC'
integer*4 ls1, ls2, i
write(*,*) ' File (without extension): '
read(*,'(a8)') filin
c first file
dummy=filin // doc
ls1 = len_trim(dummy)
ls2=0
do i = 1,ls1
if(dummy(i:i).ne.' ') then
ls2=ls2+1
file1(ls2:ls2) = dummy(i:i)
endif
enddo
c second file
dummy=filin // img
ls1 = len_trim(dummy)
ls2=0
do i = 1,ls1
if(dummy(i:i).ne.' ') then
ls2=ls2+1
file2(ls2:ls2) = dummy(i:i)
endif
enddo
write(*,*) file1
write(*,*) file2
stop
end
Thanks a lot for your hint!!

You never set the value of the whole file1 and file2 so the characters, which you do not explicitly set to something, can be anything.
At the beginning you can set initialize the strings as
file1 = ''
file2 = ''
and they will be filled with spaces which is what you need.
But you probably just want:
file1 = trim(filin) // doc
file2 = trim(filin) // img
instead all of that complicated code.

Related

Error counting substrings from file in Fortran 95

I'm trying to write a code in Fortran 95 that read strings from a file and then print a frequency table of letters from the file. The file has a text like the example below, with no more than 128 characters per line:
Ablblb lbla sdrtwfwefw
Waerfaw efeafawef awef
Pefwae fwefawefw efawe
Fcicnj ioejo, o njcdid
Pweko jai, wadwed awdd
So I did one program that is working fine for the first letter (A or a), but the counter doesn't work for the rest of the letters and always print "0". This is what I did:
program read_file
implicit none
integer :: count, i, j, k, n
character(len=80) :: arch
character(len=128) :: line
character :: c, d
logical :: rexist
print *,'Name of the file (example: "text1.txt"): '
read *,arch
count=0
inquire(file=arch, exist=rexist)
if(rexist) then
open(unit=10, file=arch)
j=97
do i=65,90
c=achar(i)
d=achar(j)
do
read(unit=10, fmt='(A128)', end=999)line
n=len_trim(line)
do k=1,n
if(line(k:k)==c .or. line(k:k)==d)then
count=count+1
end if
end do
cycle
999 exit
end do
print *, "Letter ", c, " or ", d, " Total: ", count
j=j+1
count=0
end do
close(unit=10)
else
print *,"Invalid file!"
end if
end program read_file
The first count works fine (letter A or a) but it prints "0" for the rest of the letters. Is there something wrong with the DO loop that doesn't reset the variable count properly?

How can I read the number of lines in Fortran 90 from a text file?

How can I read the number of lines present in a text file?
My text file seems to be like:
1
2
3
.
.
.
n
Use:
nlines = 0
OPEN (1, file = 'file.txt')
DO
READ (1,*, END=10)
nlines = nlines + 1
END DO
10 CLOSE (1)
print*, nlines
end
Or:
nlines = 0
OPEN (1, file = 'file.txt')
DO
READ(1,*,iostat=io)
IF (io/=0) EXIT
nlines = nlines + 1
END DO
CLOSE (1)
print*, nlines
Although it is unclear, I think if you just have to know the number lines in the files, just use wc -l <filename> on the command line.
If you want to do anything further, just read the number of lines in a character string and count until the end of file is encountered. Here is the code below:
character :: inputline*200
OPEN(lin, file=inputfile, status='old', action='read', position='rewind')
loop1: DO
READ(lin,*,iostat=eastat) inputline
IF (eastat < 0) THEN
numvalues = numvalues + 1
WRITE(*,*) trim(inputfile), ' :number of records =', numvalues-1
EXIT loop1
ELSE IF (eastat > 0) THEN
STOP 'IO-error'
ENDIF
numvalues = numvalues + 1
END DO loop1

Removing whitespace in string

I have the following code:
program main
character (len=15) :: abc = "te st tex t"
print *, trim(abc)
end program main
Which outputs:
te st tex t
I excepted all the whitespace to be removed but it wasn't. How can I remove all the whitespace from the string?
Trim will remove spaces only at the edges, not in the middle (this is common behaviour on almost all languages/libraries). If you want to remove all spaces in the string, you will have to create your own function to do this, iterating through the string.
Ex.:
program Test
implicit none
! Variables
character(len=200) :: string
! Body of Test
string = 'Hello World 7 9'
print *, string
call StripSpaces (string)
print *, string
contains
subroutine StripSpaces(string)
character(len=*) :: string
integer :: stringLen
integer :: last, actual
stringLen = len (string)
last = 1
actual = 1
do while (actual < stringLen)
if (string(last:last) == ' ') then
actual = actual + 1
string(last:last) = string(actual:actual)
string(actual:actual) = ' '
else
last = last + 1
if (actual < last) &
actual = last
endif
end do
end subroutine
end program Test
This was tested on intel compiler, not on gfortran, but I think it will work.
I was able to do this using the variable string library described here ( http://schonfelder.co.uk/is1539-2-99.htm ). The source code link is found in the introduction section of the ISO document.
Here is the code
program Console1
use ISO_VARYING_STRING
implicit none
! Body of Console1
character(LEN=50) :: text = 'Hello World John Mary '
character(LEN=50) :: res
print *, trim(text)
! 'Hello World John Mary'
res = REPLACE(text,' ','', every=.TRUE.)
print *, trim(res)
! 'HelloWorldJohnMary'
end program Console1
Here's a dirty, shameful way to eliminate the spaces. This is only likely to work if a compiler lays out a length-15 string in the same order and space as it would a 15-element array of characters. While this is likely to be true, and in my recent experience is true, it is not guaranteed to be so by the standard. That aside, this approach may be good enough.
! declarations
CHARACTER (len=15) :: abc = "te st tex t"
CHARACTER, DIMENSION(LEN(abc)) :: abc_array
! or CHARACTER, DIMENSION(:), ALLOCATABLE :: abc_array if your compiler supports
! automatic allocation
! transfer the string into an array of characters
abc_array = TRANSFER(abc,abc_array)
! eliminate the spaces, and transfer back to the string
abc = TRANSFER(PACK(abc_array,abc_array/=' '),abc)
! now all the spaces are at the end of abc so the following statement writes the
! string with no spaces
WRITE(*,*) TRIM(abc)
Use this approach at your own risk.
For those averse to TRANSFER perhaps a nice little recursive function would appeal. As written this depends on Fortran 2003's ability to automatically allocate character scalars, but it shouldn't be too hard to modify if your compiler doesn't support this feature yet.
RECURSIVE FUNCTION stripper(string,ch) RESULT(stripped)
CHARACTER(len=*), INTENT(in) :: string
CHARACTER, INTENT(in) :: ch
CHARACTER(:), ALLOCATABLE :: stripped
IF (LEN(string)==1) THEN
IF (string==ch) THEN
stripped = ''
ELSE
stripped = string
END IF
ELSE
IF (string(1:1)==ch) THEN
stripped = stripper(string(2:),ch)
ELSE
stripped = string(1:1)//stripper(string(2:),ch)
END IF
END IF
END FUNCTION stripper
You can try this:
program test
!erase blank space in a string
!run over every character of the string and just take every non-blank in other variable.
implicit none
character (len=100) str1,str2
integer i
str2='' !in this variable will be save non-blank spaces
str1=' a b c de ' !Test string with blank spaces
write(*,*)len_trim(str1), str1
do i=1,len(str1)
if (str1(i:i).ne.' ')str2=trim(str2)//trim(str1(i:i))
end do
write(*,*)len_trim(str2), str2
end

reading delimiter with fortran

I need to read this kind of file. I have problem reading the delimiters within the file.
xxxx
dd/mm/yyyy
text
text
angle
Number of points
-13.82|654781.695|292510.337|4.889|SD
0.00|654795.515|292510.337|4.373|P1
1.25|654796.765|292510.337|4.324|SD
1.29|654796.805|292510.337|4.657|SD
1.68|654797.195|292510.337|4.622|SD
......
(1) Read lines from the file into a string using the "(a)" format.
(2) Replace unwanted delimiters in the string with delimiters recognized by Fortran (spaces or commas).
(3) Get data from the string using an "internal read".
The program below illustrates steps (2) and (3).
program main
implicit none
character (len=20) :: str
integer :: i
real :: x,y
str = "321.1|5678.9"
do i=1,len_trim(str)
if (str(i:i) == "|") str(i:i) = " "
end do
print*,"str = '" // trim(str) // "'" ! output: '321.1 5678.9'
read (str,*) x,y
print*,"x, y =",x,y ! output: x, y = 321.1 5678.9
end program main

Use regexp in Matlab to return the value of a variable from a text file

I am reading a text file into Matlab called 'test.txt' which is structured as follows:
$variable1 = answer1;
$variable2 = answer2;
$variable3 = answer3;
I read the text file into Matlab line by line using the following segment of code:
fid = fopen('test.txt.');
tline = fgetl(fid);
tracks = {};
while ischar(tline)
tracks{end+1} = regexp(tline, '(?<=^.*\=\s*)(.*)(?=\s*;$)', 'match', 'once');
tline = fgetl(fid);
end
fclose(fid);
This piece of code returns the value of each variable line by line and would output:
answer1
answer2
answer3
What I want to do is modify my regexp expression so that I can specify the name of the variable to retrieve and have Matlab output the value assigned to the variable specified.
E.g. If I specify in my code to find the value of $variable2, Matlab would return:
answer2
Regards
One possible solution:
function [tracks] = GetAnswer(Filename, VariableName)
fid = fopen(Filename);
tline = fgetl(fid);
tracks = {};
% prefix all $ in VariableName with \ for `regexp` and `regexprep`
VariableName = regexprep(VariableName, '\$', '\\$');
while ischar(tline)
if (regexp(tline, [ '(', VariableName, ')', '( = )', '(.*)', '(;)' ]))
tracks{end+1} = regexprep(tline, [ '(', VariableName, ')', '( = )', '(.*)', '(;)' ], '$3');
% if you want all matches (not only the 1st one),
% remove the following `break` line.
break;
end
tline = fgetl(fid);
end
fclose(fid);
return
You can call it this way:
Answer = GetAnswer('test.txt', '$variable2')
Answer =
'answer2'