Skyy2010
Skyy2010

Reputation: 855

Unable to compile function which returns parts of a string

I want to use following function in my code. I want it to take given string, cut all leading zeros and return a string without the leading zeros. For example I give it '00023' and it shall return '23___' (_ is space) I have this function in my code:

function cut_zeros(string)
implicit none
    character(5) :: cut_zeros, string
    integer:: string_limit, i

    string_limit = 5

    do i= 1, string_limit
        if (string(i)/='0') then
            cut_zeros = string(i : string_limit)
            exit
        endif
    enddo

end function cut_zeros

I really don't know what problem the compiler has. It gives this information:

   cut_zeros = string(i : string_limit)
                        1
Error: Syntax error in argument list at (1)

I also have another question? Is it possible to make the function assumed length? So that I can pass a string of any length to it? As far as I understand it is not possible, because the return value of a function cannot be assumed length, right?

Upvotes: 0

Views: 102

Answers (3)

High Performance Mark
High Performance Mark

Reputation: 78364

Or you could use Fortran's existing capabilities

  CHARACTER(6) :: src = '002305'
  CHARACTER(LEN(src)) :: dest
  ...
  dest = src(SCAN(src,'123456789'):)
  ! now dest is '2305__'

This only works if the first non-0 character is another digit, if you have other characters to worry about extend the set used in the 2nd argument to SCAN.

Upvotes: 1

Alexander Vogt
Alexander Vogt

Reputation: 18118

The error message is actually misleading. The error happens one line above: to compare the i-th character, you need to use string(i:i). If you change that line to

if (string(i:i)/='0') then

the code works as expected.

For the second part of your question, you can use assumed length strings! You can simply set the length of the return value to the length of the input string:

function cut_zeros(string)
implicit none
    character(*) :: string
    character(len=len(string)) :: cut_zeros
    integer:: string_limit, i

    string_limit = len(string)

    do i= 1, string_limit
        if (string(i:i)/='0') then
            cut_zeros = string(i : string_limit)
            exit
        endif
    enddo
end function cut_zeros

Here, the length of the return string is chosen that if no zeroes are removed, it still has a valid length. Note that you will require an interface to handle assumed length dummy arguments.

To crop the output string to the exact length required you would need allocatable strings which is not fully supported by all compilers:

function cut_zeros(string)
implicit none
    character(*) :: string
    character(len=:),allocatable :: cut_zeros
    integer:: string_limit, i

    string_limit = len(string)

    do i= 1, string_limit
        if (string(i:i)/='0') then
            allocate( character(len=string_limit-i+1) :: cut_zeros )
            cut_zeros = string(i : string_limit)
            exit
        endif
    enddo
end function cut_zeros

Upvotes: 4

IanH
IanH

Reputation: 21451

The syntax for a substring reference requires the separating colon, i.e. you want string(i:i). If you don't have that colon, the compiler considers that syntax to be a function reference (it knows it isn't an array reference, because you didn't declare string as an array).

You don't want an assumed length function. Such a thing exists, but they are an anachronism that is best forgotten. What you may want is an automatic length function, where the length of the function result depends on the input.

FUNCTION cut_zeros(string)
  CHARACTER(*), INTENT(IN) :: string
  ! The length of the function result is the same as the length 
  ! of the argument.
  CHARACTER(LEN(string)) :: cut_zeros

A function with an automatic result requires an explicit interface in any scope where it is referenced. Best off putting it in a module, and USE'ing the module.

Upvotes: 0

Related Questions