Why does the output appear black? - fortran

Operating System : Windows 10
Compiler : XStart
Command when running the program : pgf90 prgramname.f90
running program command : a.out
Program code I wrote :
Program silta
implicit none
CHARACTER :: Str_1 = " For", Str_2 =" tran", z
z = Str_1 // Str_2 // " -90"
print *, z
end program silta
When I run this program, there is no result and only black space.
Probably the result of the problem is the Fortran-90, but how do I get it to print properly?

This line
CHARACTER :: Str_1 = " For", Str_2 =" tran", z
declares 3 character variables, each one character long. What you get, therefore, is str1 == " ", str2 == " " and z unset. Then this line
z = Str_1 // Str_2 // " -90"
is interpreted as
z = " " // " " // " -90"
but only the first character, which is a space, gets into z. And that's what you see when you print it out, or rather, that's what you don't see, it's just a space.
Go back to your Fortran tutorial and learn about character lengths, perhaps start with
CHARACTER(len=8) :: Str_1 = " For", Str_2 =" tran", z
As VladimirF has commented, learn also the intrinsic function trim for getting rid of trailing spaces in character variables. There are other useful intrinsic string functions too, worthy of your research.

Related

INDEX is not returning a match when using a variable substring

I have compiled code with gfortran and AOCC flang compiler, but it fails for both, is there anything wrong I am doing?
program find_sub_indx
implicit none
!decl
character(len =30) :: main_string, sub_string
integer :: index_1 , index_2
logical :: back
!defn
main_string = "this is the main string"
sub_string = "a"
back = .false.
index_1 = INDEX(main_string, sub_string, back) !why does this not work
index_2 = INDEX("this is the main string","a", .false.) !this works why?
print *, "index_1 is " , index_1, index_2
end program find_sub_indx
Result expected:
index_1 is 14 14
Actual result:
index_1 is 0 14
Is there some standard reference for learning fortran, as I couldn't find the proper definition of intrinsic function used above.
In the first attempt to use index
INDEX(main_string, sub_string, back)
the variables main_string and sub_string are both of length 30. After the assignment
sub_string = "a"
the variable sub_string has value starting with a but has 29 trailing spaces after that.
So, the function is evaluated like
INDEX(main_string, 'a ', back)
That substring is, of course, not found in main_string and the result is correctly 0.
You can instead use
INDEX(main_string, TRIM(sub_string), back) !or
INDEX(main_string, sub_string(1:1), back)
or declare sub_string to be of length 1.
The literal constant "a" in the second attempt has length 1 and does not have these trailing spaces.

Format: add trailing spaces to character output to left-justify

How do you format a string to have constant width and be left-justified? There is the Aw formatter, where w denotes desired width of character output, but it prepends the spaces if w > len(characters), instead of appending them.
When I try
44 format(A15)
print 44, 'Hi Stack Overflow'
I get
> Hi Stack Overflow<
instead of
>Hi Stack Overflow <
Is there any simple Fortran formatting solution that solves this?
As noted in the question, the problem is that when a character expression of length shorter than the output field width the padding spaces appear before the character expression. What we want is for the padding spaces to come after our desired string.
There isn't a simple formatting solution, in the sense of a natural edit descriptor. However, what we can do is output an expression with sufficient trailing spaces (which count towards the length).
For example:
print '(A50)', 'Hello'//REPEAT(' ',50)
or
character(50) :: hello='Hello'
print '(A50)', hello
or even
print '(A50)', [character(50) :: 'hello']
That is, in each case the output item is a character of length (at least) 50. Each will be padded on the right with blanks.
If you chose, you could even make a function which returns the extended (left-justified) expression:
print '(A50)', right_pad('Hello')
where the function is left as an exercise for the reader.
To complete #francescalus excellent answer for future reference, the proposed solution also works in case of allocatables in place of string literals:
character(len=:), allocatable :: a_str
a_str = "foobar"
write (*,"(A,I4)") a_str, 42
write (*,"(A,I4)") [character(len=20) :: a_str], 42
will output
foobar 42
foobar 42
a bit ugly but you can concatenate a blank string:
character*15 :: blank=' '
print 44, 'Hi Stack Overflow'//blank
program test ! Write left justified constant width character columns
! declare some strings.
character(len=32) :: str1,str2,str3,str4,str5,str6
! define the string values.
str1 = " Nina "; str2 = " Alba " ; str3 = " blue "
str4 = " Jamil "; str5 = " Arnost " ; str6 = " green "
write(*,'(a)') "123456789012345678901234567890"
! format to 3 columns 10 character wide each.
! and adjust the stings to the left.
write(*,'(3(a10))') adjustl(str1), adjustl(str2), adjustl(str3)
write(*,'(3(a10))') adjustl(str4), adjustl(str5), adjustl(str6)
end program test
$ ./a.out
123456789012345678901234567890
Nina Alba blue
Jamil Arnost green
adjustl() moves leading spaces to the end of the string.
I suggest that you do not limit the number of output characters.
Change it to the following will work:
44 format(A)
print 44, 'Hi Stack Overflow'

How to invoke a program and pass it standard input

How do I invoke a program and pass it standard input? Hypothetical example in Bash:
(echo abc; echo abba) | tr b B
Note that:
I don't have the input in a string (I'm generating it as I iterate)
I don't know how long input is
The input may span multiple lines, as in this example
I've written this in 19 other languages already, the way I usually approach it is to get a file descriptor for the program's standard input, and then write to the file descriptor the same way I would write to standard output.
What I've tried so far: Based on Invoke external program and pass arguments I tried passing it to echo and using the shell to handle the piping. This doesn't work if my input has single quotes in it, and it doesn't work if I don't have my input in a string (which I don't)
Here is my code, currently trying to pull it off by calculating the string that will be printed (it fails right now).
As for single quotation, how about inserting the escape character (\) before each quotation mark (')...? It seems to be working somehow for the "minimal" example:
module utils
implicit none
contains
function esc( inp ) result( ret )
character(*), intent(in) :: inp
character(:), allocatable :: ret
integer :: i
ret = ""
do i = 1, len_trim( inp )
if ( inp( i:i ) == "'" ) then
ret = ret // "\'"
else
ret = ret // inp( i:i )
endif
enddo
endfunction
endmodule
program test
use utils
implicit none
character(100) :: str1, str2
integer i
call getcwd( str1 ) !! to test a directory name containing single quotes
str2 = "ab'ba"
print *, "trim(str1) = ", trim( str1 )
print *, "trim(str2) = ", trim( str2 )
print *
print *, "esc(str1) = ", esc( str1 )
print *, "esc(str2) = ", esc( str2 )
print *
print *, "using raw str1:"
call system( "echo " // trim(str1) // " | tr b B" )
print *
print *, "using raw str2:"
call system( "echo " // trim(str2) // " | tr b B" ) !! error
print *
print *, "using esc( str1 ):"
call system( "echo " // esc(str1) // " | tr b B" )
print *
print *, "using esc( str2 ):"
call system( "echo " // esc(str2) // " | tr b B" )
print *
print *, "using esc( str1 ) and esc( str2 ):"
call system( "(echo " // esc(str1) // "; echo " // esc(str2) // ") | tr b B" )
! pbcopy (copy to pasteboard; mac-only)
! call system( "(echo " // esc(str1) // "; echo " // esc(str2) // ") | pbcopy" )
endprogram
If we run the above program in the directory /foo/baa/x\'b\'z, we obtain
trim(str1) = /foo/baa/x'b'y
trim(str2) = ab'ba
esc(str1) = /foo/baa/x\'b\'y
esc(str2) = ab\'ba
using raw str1:
/foo/baa/xBy
using raw str2:
sh: -c: line 0: unexpected EOF while looking for matching `''
sh: -c: line 1: syntax error: unexpected end of file
using esc( str1 ):
/foo/baa/x'B'y
using esc( str2 ):
aB'Ba
using esc( str1 ) and esc( str2 ):
/foo/baa/x'B'y
aB'Ba
This is what I mean by a minimal example.
call execute_command_line("(echo ""hexxo world"";echo abba)|tr x l")
end
hello world
abba
Is this not doing exactly what you ask, invoking tr and passing standard input?

Spaces in fortran string output

I have the following Fortran 95 code:
program write_test
CHARACTER(LEN=3) :: str
write(*,*) (' ',"""",'File'//trim(str(i)),"""",' ',"""",'Frequency'//trim(str(i)),"""",i=1,5)
end program write_test
!character*(*) function str(k)
character(*) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
When I compile and run it, I get the following output:
" File1" " Frequency1" " File2" " Frequency2" " File3" " Frequency3" " File4" " Frequency4" " File5" " Frequency5"
Why is there a space between the double quote and the letter F?
For list-directed output with the * "format", the compiler has freedom to insert one or more spaces between the items printed. For more precise control, use a format string, as in the code below, tested with g95 and gfortran. You can use the i0 format to print an integer without spaces.
program write_test
character(len=3) :: str
write (*,"(100a)") (" ","""","File"//trim(str(i)),"""", &
" ","""","Frequency"//trim(str(i)),"""",i=1,5)
! preferred way is line below
write (*,"(100(1x,2a,i0,a))") ("""","File",i,"""","""","Frequency",i,"""",i=1,5)
end program write_test
character(*) function str(k)
! Convert an integer to string
integer, intent(in) :: k
write (str,"(i0)") k
str = adjustl(str)
end function str

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