I have to make an app that edits a todo list (file to_do.txt). I can read it and also I can add new tasks, but I cannot remove a specific line of the file without destroying everything. How can I do it? This is my code
program compito4
implicit none
! Declaring the variables
integer :: unit, stat, counter, i
character (len = 1) action
character (len = 200) line, new_task
! Open the program
open(newunit = unit, file = 'to_do.txt', status = 'OLD', position = 'APPEND')
do
print *, 'What would you like to do? (a)dd, (d)elete, (l)ist, (q)uit'
read (*,*) action
if (action == 'a') then
print *, 'Insert the new task'
read (*, '(A)') new_task
write (unit, '(A)') '\n' // new_task ! // is the string concatenation operator
print *, 'New task successfully added'
else if (action == 'd') then
print *, 'Insert the number of the task to be removed'
read (*,*) i
print *, i
counter = 0
rewind unit
do
read(unit, '(A)', iostat = stat) line
if (stat .ne. 0) then
backspace unit
exit
else if (i == counter) then
print *, 'You are in the right spot'
print *, counter
backspace unit
write (unit, '(2A)') trim(line), ('->Task done')
end if
counter = counter + 1
end do
else if (action == 'l') then
rewind unit
counter = 0
do
read(unit, '(A)', iostat = stat) line
if (stat .ne. 0) then ! It handles the end of file!
backspace unit
exit
end if
print *, counter,') ', line
counter = counter + 1
end do
else if (action == 'q') then
print *, 'Closing the program'
exit
else
print *, 'Invalid choice'
end if
end do
close(unit)
end program compito4
Related
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?
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.
I've got a simple routine that never quits
import sys
infile = sys.argv[1]
outfile = sys.argv[2]
count=1
print 'Input file is ', infile
print 'Output file is ', outfile
instream = open(infile,'r')
while True:
line=instream.readline()
if line[0:5]=='<?xml':
print 'new record', count
count=count+1
if line == "eof":
print 'end'
break
This reads the infield... but never ends. What do I need to do?
readline() doesn't return the string eof to signify the end of the file; it returns the empty string. (Note readline retains the newline that terminates each line, so a blank line would be represented as '\n'; so a truly blank line can only mean that no data is left.)
You could write
while True:
line = instream.readline()
# ...
if line == "":
break
but usually you simply treat the file as an iterator:
for line in instream:
if line[0:5] == '<?xml':
print 'new record', count
count = count + 1
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
I'm trying to read a file line by line using a DO and read to manipulate individual lines. However, I'm trying to skip a line wherever I see something I don't want.
Here's what I have so far:
DO J=1,10000
READ(1,'(A150)') ROW
IF (J==A(1)+1 .AND. ROW(17:17)=='|') THEN
WRITE(2, '(A)') ROW(1:12) // ROW(15:150)
ELSEIF (J>A(1) .AND. J<A(2) .AND. ROW(1:1)=='#') THEN
! Here's where I need to skip J and go onto J+1 and then continue the DO loop from there
END IF
END DO
How can I do it?
Use CYCLE:
DO J=1,10000
READ(1,'(A150)') ROW
IF ((J==A(1)+1) .AND. (ROW(17:17).EQ.'|')) THEN
WRITE(2, '(A)') ROW(1:12) // ROW(15:150)
ELSEIF (J.GT.A(1) .AND. J.LT.A(2) .AND. ROW(1:1)=='#') THEN
CYCLE
END IF
! More statements here
END DO
As Hristo pointed out, CYCLE is only necessary if you have more statements following the IF ... END IF.