String Functions in Fortran

Our first program will demonstrate various string operations in Fortran. Here’s the full source code:

program string_functions
    use iso_fortran_env, only: stdout => output_unit
    implicit none
    
    ! Declare variables
    character(len=:), allocatable :: str1, str2, result
    logical :: contains, has_prefix, has_suffix
    integer :: count, index_pos
    character(len=:), allocatable :: joined, repeated, replaced
    character(len=10), dimension(5) :: split_result
    
    ! Define a subroutine for printing
    interface
        subroutine print_result(label, value)
            character(len=*), intent(in) :: label
            class(*), intent(in) :: value
        end subroutine print_result
    end interface
    
    ! String operations
    str1 = "test"
    str2 = "es"
    
    ! Contains
    contains = index(str1, str2) > 0
    call print_result("Contains:  ", contains)
    
    ! Count
    count = count_substring(str1, "t")
    call print_result("Count:     ", count)
    
    ! HasPrefix
    has_prefix = str1(1:2) == "te"
    call print_result("HasPrefix: ", has_prefix)
    
    ! HasSuffix
    has_suffix = str1(len(str1)-1:) == "st"
    call print_result("HasSuffix: ", has_suffix)
    
    ! Index
    index_pos = index(str1, "e")
    call print_result("Index:     ", index_pos)
    
    ! Join
    joined = join(["a", "b"], "-")
    call print_result("Join:      ", joined)
    
    ! Repeat
    repeated = repeat("a", 5)
    call print_result("Repeat:    ", repeated)
    
    ! Replace
    replaced = replace_all("foo", "o", "0")
    call print_result("Replace:   ", replaced)
    
    replaced = replace_first("foo", "o", "0")
    call print_result("Replace:   ", replaced)
    
    ! Split
    call split("a-b-c-d-e", "-", split_result)
    call print_result("Split:     ", split_result)
    
    ! ToLower
    result = to_lower("TEST")
    call print_result("ToLower:   ", result)
    
    ! ToUpper
    result = to_upper("test")
    call print_result("ToUpper:   ", result)

contains

    function count_substring(str, substr) result(count)
        character(len=*), intent(in) :: str, substr
        integer :: count, i
        count = 0
        i = 1
        do while (i <= len(str) - len(substr) + 1)
            if (str(i:i+len(substr)-1) == substr) then
                count = count + 1
                i = i + len(substr)
            else
                i = i + 1
            end if
        end do
    end function count_substring

    function join(arr, sep) result(joined)
        character(len=*), dimension(:), intent(in) :: arr
        character(len=*), intent(in) :: sep
        character(len=:), allocatable :: joined
        integer :: i
        joined = arr(1)
        do i = 2, size(arr)
            joined = joined // sep // arr(i)
        end do
    end function join

    function replace_all(str, old, new) result(replaced)
        character(len=*), intent(in) :: str, old, new
        character(len=:), allocatable :: replaced
        integer :: i
        replaced = str
        do i = 1, len(str) - len(old) + 1
            if (replaced(i:i+len(old)-1) == old) then
                replaced = replaced(:i-1) // new // replaced(i+len(old):)
            end if
        end do
    end function replace_all

    function replace_first(str, old, new) result(replaced)
        character(len=*), intent(in) :: str, old, new
        character(len=:), allocatable :: replaced
        integer :: i
        replaced = str
        do i = 1, len(str) - len(old) + 1
            if (replaced(i:i+len(old)-1) == old) then
                replaced = replaced(:i-1) // new // replaced(i+len(old):)
                exit
            end if
        end do
    end function replace_first

    subroutine split(str, sep, result)
        character(len=*), intent(in) :: str, sep
        character(len=*), dimension(:), intent(out) :: result
        integer :: i, j, k
        i = 1
        k = 1
        do j = 1, len(str)
            if (str(j:j) == sep .or. j == len(str)) then
                if (j == len(str)) j = j + 1
                result(k) = str(i:j-1)
                i = j + 1
                k = k + 1
            end if
        end do
    end subroutine split

    function to_lower(str) result(lower)
        character(len=*), intent(in) :: str
        character(len=:), allocatable :: lower
        integer :: i, j
        lower = str
        do i = 1, len(str)
            j = iachar(str(i:i))
            if (j >= iachar('A') .and. j <= iachar('Z')) then
                lower(i:i) = achar(j + 32)
            end if
        end do
    end function to_lower

    function to_upper(str) result(upper)
        character(len=*), intent(in) :: str
        character(len=:), allocatable :: upper
        integer :: i, j
        upper = str
        do i = 1, len(str)
            j = iachar(str(i:i))
            if (j >= iachar('a') .and. j <= iachar('z')) then
                upper(i:i) = achar(j - 32)
            end if
        end do
    end function to_upper

    subroutine print_result(label, value)
        character(len=*), intent(in) :: label
        class(*), intent(in) :: value
        select type (value)
            type is (logical)
                if (value) then
                    write(stdout, '(a,l1)') label, value
                else
                    write(stdout, '(a,l1)') label, value
                end if
            type is (integer)
                write(stdout, '(a,i0)') label, value
            type is (character(*))
                write(stdout, '(a,a)') label, value
            type is (character(*), dimension(*))
                write(stdout, '(a,5(a,1x))') label, value
        end select
    end subroutine print_result

end program string_functions

This program demonstrates various string operations in Fortran. Here’s a breakdown of what each operation does:

  1. Contains: Checks if a substring is present in a string.
  2. Count: Counts the occurrences of a substring in a string.
  3. HasPrefix: Checks if a string starts with a specific prefix.
  4. HasSuffix: Checks if a string ends with a specific suffix.
  5. Index: Finds the position of a substring in a string.
  6. Join: Concatenates an array of strings with a separator.
  7. Repeat: Repeats a string a specified number of times.
  8. Replace: Replaces all occurrences or the first occurrence of a substring.
  9. Split: Splits a string into an array of substrings based on a separator.
  10. ToLower: Converts a string to lowercase.
  11. ToUpper: Converts a string to uppercase.

To run the program, save it as string_functions.f90 and compile it using a Fortran compiler:

$ gfortran string_functions.f90 -o string_functions
$ ./string_functions
Contains:   T
Count:      2
HasPrefix:  T
HasSuffix:  T
Index:      2
Join:      a-b
Repeat:    aaaaa
Replace:   f00
Replace:   f0o
Split:     a b c d e 
ToLower:   test
ToUpper:   TEST

This example showcases how to perform various string operations in Fortran. Note that Fortran doesn’t have a built-in string manipulation module as extensive as some other languages, so we’ve implemented some of these functions manually.