! SPDX-Identifier: MIT #:include "common.fypp" !> This module implements basic string handling routines. !> !> The specification of this module is available [here](../page/specs/stdlib_strings.html). module stdlib_strings use stdlib_ascii, only: whitespace use stdlib_string_type, only: string_type, char, verify, repeat, len use stdlib_optval, only: optval use stdlib_kinds, only: sp, dp, xdp, qp, int8, int16, int32, int64, lk, c_bool implicit none private public :: to_string public :: strip, chomp public :: starts_with, ends_with public :: slice, find, replace_all, padl, padr, count, zfill !> Version: experimental !> !> Format or transfer other types as a string. !> ([Specification](../page/specs/stdlib_strings.html#to_string)) interface to_string #:set RC_KINDS_TYPES = REAL_KINDS_TYPES + CMPLX_KINDS_TYPES #:set IL_KINDS_TYPES = INT_KINDS_TYPES + LOG_KINDS_TYPES #:for k1, t1 in RC_KINDS_TYPES pure module function to_string_${t1[0]}$_${k1}$(value, format) result(string) ${t1}$, intent(in) :: value character(len=*), intent(in), optional :: format character(len=:), allocatable :: string end function to_string_${t1[0]}$_${k1}$ #:endfor #:for k1, t1 in IL_KINDS_TYPES pure module function to_string_1_${t1[0]}$_${k1}$(value) result(string) ${t1}$, intent(in) :: value character(len=#{if t1[0]=="l"}#1)#{else}#:), allocatable#{endif}# :: string end function to_string_1_${t1[0]}$_${k1}$ pure module function to_string_2_${t1[0]}$_${k1}$(value, format) result(string) ${t1}$, intent(in) :: value character(len=*), intent(in) :: format character(len=:), allocatable :: string end function to_string_2_${t1[0]}$_${k1}$ #:endfor end interface to_string !> Remove leading and trailing whitespace characters. !> !> Version: experimental interface strip module procedure :: strip_string module procedure :: strip_char end interface strip !> Remove trailing characters in set from string. !> If no character set is provided trailing whitespace is removed. !> !> Version: experimental interface chomp module procedure :: chomp_string module procedure :: chomp_char module procedure :: chomp_set_string_char module procedure :: chomp_set_char_char module procedure :: chomp_substring_string_string module procedure :: chomp_substring_char_string module procedure :: chomp_substring_string_char module procedure :: chomp_substring_char_char end interface chomp !> Check whether a string starts with substring or not !> !> Version: experimental interface starts_with module procedure :: starts_with_string_string module procedure :: starts_with_string_char module procedure :: starts_with_char_string module procedure :: starts_with_char_char end interface starts_with !> Check whether a string ends with substring or not !> !> Version: experimental interface ends_with module procedure :: ends_with_string_string module procedure :: ends_with_string_char module procedure :: ends_with_char_string module procedure :: ends_with_char_char end interface ends_with !> Extracts characters from the input string to return a new string !> !> Version: experimental interface slice module procedure :: slice_string module procedure :: slice_char end interface slice !> Finds the starting index of substring 'pattern' in the input 'string' !> [Specifications](link to the specs - to be completed) !> !> Version: experimental interface find module procedure :: find_string_string module procedure :: find_string_char module procedure :: find_char_string module procedure :: find_char_char end interface find !> Replaces all the occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Version: experimental interface replace_all module procedure :: replace_all_string_string_string module procedure :: replace_all_string_string_char module procedure :: replace_all_string_char_string module procedure :: replace_all_char_string_string module procedure :: replace_all_string_char_char module procedure :: replace_all_char_string_char module procedure :: replace_all_char_char_string module procedure :: replace_all_char_char_char end interface replace_all !> Version: experimental !> !> Left pad the input string !> [Specifications](../page/specs/stdlib_strings.html#padl) interface padl module procedure :: padl_string_default module procedure :: padl_string_pad_with module procedure :: padl_char_default module procedure :: padl_char_pad_with end interface padl !> Version: experimental !> !> Right pad the input string !> [Specifications](../page/specs/stdlib_strings.html#padr) interface padr module procedure :: padr_string_default module procedure :: padr_string_pad_with module procedure :: padr_char_default module procedure :: padr_char_pad_with end interface padr !> Version: experimental !> !> Returns the number of times substring 'pattern' has appeared in the !> input string 'string' !> [Specifications](../page/specs/stdlib_strings.html#count) interface count module procedure :: count_string_string module procedure :: count_string_char module procedure :: count_char_string module procedure :: count_char_char end interface count !> Version: experimental !> !> Left pad the input string with zeros. !> [Specifications](../page/specs/stdlib_strings.html#zfill) interface zfill module procedure :: zfill_string module procedure :: zfill_char end interface zfill contains !> Remove leading and trailing whitespace characters. pure function strip_string(string) result(stripped_string) ! Avoid polluting the module scope and use the assignment only in this scope use stdlib_string_type, only : assignment(=) type(string_type), intent(in) :: string type(string_type) :: stripped_string stripped_string = strip(char(string)) end function strip_string !> Remove leading and trailing whitespace characters. pure function strip_char(string) result(stripped_string) character(len=*), intent(in) :: string character(len=:), allocatable :: stripped_string integer :: first, last first = verify(string, whitespace) if (first == 0) then stripped_string = "" else last = verify(string, whitespace, back=.true.) stripped_string = string(first:last) end if end function strip_char !> Remove trailing characters in set from string. !> Default character set variant where trailing whitespace is removed. pure function chomp_string(string) result(chomped_string) ! Avoid polluting the module scope and use the assignment only in this scope use stdlib_string_type, only : assignment(=) type(string_type), intent(in) :: string type(string_type) :: chomped_string integer :: last last = verify(string, whitespace, back=.true.) chomped_string = char(string, 1, last) end function chomp_string !> Remove trailing characters in set from string. !> Default character set variant where trailing whitespace is removed. pure function chomp_char(string) result(chomped_string) character(len=*), intent(in) :: string character(len=:), allocatable :: chomped_string integer :: last last = verify(string, whitespace, back=.true.) chomped_string = string(1:last) end function chomp_char !> Remove trailing characters in set from string. pure function chomp_set_string_char(string, set) result(chomped_string) ! Avoid polluting the module scope and use the assignment only in this scope use stdlib_string_type, only : assignment(=) type(string_type), intent(in) :: string character(len=1), intent(in) :: set(:) type(string_type) :: chomped_string chomped_string = chomp(char(string), set) end function chomp_set_string_char !> Remove trailing characters in set from string. pure function chomp_set_char_char(string, set) result(chomped_string) character(len=*), intent(in) :: string character(len=1), intent(in) :: set(:) character(len=:), allocatable :: chomped_string integer :: last last = verify(string, set_to_string(set), back=.true.) chomped_string = string(1:last) end function chomp_set_char_char !> Remove trailing substrings from string. pure function chomp_substring_string_string(string, substring) result(chomped_string) ! Avoid polluting the module scope and use the assignment only in this scope use stdlib_string_type, only : assignment(=) type(string_type), intent(in) :: string type(string_type), intent(in) :: substring type(string_type) :: chomped_string chomped_string = chomp(char(string), char(substring)) end function chomp_substring_string_string !> Remove trailing substrings from string. pure function chomp_substring_string_char(string, substring) result(chomped_string) ! Avoid polluting the module scope and use the assignment only in this scope use stdlib_string_type, only : assignment(=) type(string_type), intent(in) :: string character(len=*), intent(in) :: substring type(string_type) :: chomped_string chomped_string = chomp(char(string), substring) end function chomp_substring_string_char !> Remove trailing substrings from string. pure function chomp_substring_char_string(string, substring) result(chomped_string) character(len=*), intent(in) :: string type(string_type), intent(in) :: substring character(len=:), allocatable :: chomped_string chomped_string = chomp(string, char(substring)) end function chomp_substring_char_string !> Remove trailing substrings from string. pure function chomp_substring_char_char(string, substring) result(chomped_string) character(len=*), intent(in) :: string character(len=*), intent(in) :: substring character(len=:), allocatable :: chomped_string integer :: last, nsub last = len(string) nsub = len(substring) if (nsub > 0) then do while(string(last-nsub+1:last) == substring) last = last - nsub end do end if chomped_string = string(1:last) end function chomp_substring_char_char !> Implementation to transfer a set of characters to a string representing the set. !> !> This function is internal and not part of the public API. pure function set_to_string(set) result(string) character(len=1), intent(in) :: set(:) character(len=size(set)) :: string string = transfer(set, string) end function set_to_string !> Check whether a string starts with substring or not pure function starts_with_char_char(string, substring) result(match) character(len=*), intent(in) :: string character(len=*), intent(in) :: substring logical :: match integer :: nsub nsub = len(substring) if (len(string) < nsub) then match = .false. return end if match = string(1:nsub) == substring end function starts_with_char_char !> Check whether a string starts with substring or not elemental function starts_with_string_char(string, substring) result(match) type(string_type), intent(in) :: string character(len=*), intent(in) :: substring logical :: match match = starts_with(char(string), substring) end function starts_with_string_char !> Check whether a string starts with substring or not elemental function starts_with_char_string(string, substring) result(match) character(len=*), intent(in) :: string type(string_type), intent(in) :: substring logical :: match match = starts_with(string, char(substring)) end function starts_with_char_string !> Check whether a string starts with substring or not elemental function starts_with_string_string(string, substring) result(match) type(string_type), intent(in) :: string type(string_type), intent(in) :: substring logical :: match match = starts_with(char(string), char(substring)) end function starts_with_string_string !> Check whether a string ends with substring or not pure function ends_with_char_char(string, substring) result(match) character(len=*), intent(in) :: string character(len=*), intent(in) :: substring logical :: match integer :: last, nsub last = len(string) nsub = len(substring) if (last < nsub) then match = .false. return end if match = string(last-nsub+1:last) == substring end function ends_with_char_char !> Check whether a string ends with substring or not elemental function ends_with_string_char(string, substring) result(match) type(string_type), intent(in) :: string character(len=*), intent(in) :: substring logical :: match match = ends_with(char(string), substring) end function ends_with_string_char !> Check whether a string ends with substring or not elemental function ends_with_char_string(string, substring) result(match) character(len=*), intent(in) :: string type(string_type), intent(in) :: substring logical :: match match = ends_with(string, char(substring)) end function ends_with_char_string !> Check whether a string ends with substring or not elemental function ends_with_string_string(string, substring) result(match) type(string_type), intent(in) :: string type(string_type), intent(in) :: substring logical :: match match = ends_with(char(string), char(substring)) end function ends_with_string_string !> Extract the characters from the region between 'first' and 'last' index (both inclusive) !> of the input 'string' by taking strides of length 'stride' !> Returns a new string elemental function slice_string(string, first, last, stride) result(sliced_string) type(string_type), intent(in) :: string integer, intent(in), optional :: first, last, stride type(string_type) :: sliced_string sliced_string = string_type(slice(char(string), first, last, stride)) end function slice_string !> Extract the characters from the region between 'first' and 'last' index (both inclusive) !> of the input 'string' by taking strides of length 'stride' !> Returns a new string pure function slice_char(string, first, last, stride) result(sliced_string) character(len=*), intent(in) :: string integer, intent(in), optional :: first, last, stride integer :: first_index, last_index, stride_vector, strides_taken, length_string, i, j character(len=:), allocatable :: sliced_string length_string = len(string) first_index = 0 ! first_index = -infinity last_index = length_string + 1 ! last_index = +infinity stride_vector = 1 if (present(stride)) then if (stride /= 0) then if (stride < 0) then first_index = length_string + 1 ! first_index = +infinity last_index = 0 ! last_index = -infinity end if stride_vector = stride end if else if (present(first) .and. present(last)) then if (last < first) then stride_vector = -1 end if end if end if if (present(first)) then first_index = first end if if (present(last)) then last_index = last end if if (stride_vector > 0) then first_index = max(first_index, 1) last_index = min(last_index, length_string) else first_index = min(first_index, length_string) last_index = max(last_index, 1) end if strides_taken = floor( real(last_index - first_index)/real(stride_vector) ) allocate(character(len=max(0, strides_taken + 1)) :: sliced_string) j = 1 do i = first_index, last_index, stride_vector sliced_string(j:j) = string(i:i) j = j + 1 end do end function slice_char !> Returns the starting index of the 'occurrence'th occurrence of substring 'pattern' !> in input 'string' !> Returns an integer elemental function find_string_string(string, pattern, occurrence, consider_overlapping) result(res) type(string_type), intent(in) :: string type(string_type), intent(in) :: pattern integer, intent(in), optional :: occurrence logical, intent(in), optional :: consider_overlapping integer :: res res = find(char(string), char(pattern), occurrence, consider_overlapping) end function find_string_string !> Returns the starting index of the 'occurrence'th occurrence of substring 'pattern' !> in input 'string' !> Returns an integer elemental function find_string_char(string, pattern, occurrence, consider_overlapping) result(res) type(string_type), intent(in) :: string character(len=*), intent(in) :: pattern integer, intent(in), optional :: occurrence logical, intent(in), optional :: consider_overlapping integer :: res res = find(char(string), pattern, occurrence, consider_overlapping) end function find_string_char !> Returns the starting index of the 'occurrence'th occurrence of substring 'pattern' !> in input 'string' !> Returns an integer elemental function find_char_string(string, pattern, occurrence, consider_overlapping) result(res) character(len=*), intent(in) :: string type(string_type), intent(in) :: pattern integer, intent(in), optional :: occurrence logical, intent(in), optional :: consider_overlapping integer :: res res = find(string, char(pattern), occurrence, consider_overlapping) end function find_char_string !> Returns the starting index of the 'occurrence'th occurrence of substring 'pattern' !> in input 'string' !> Returns an integer elemental function find_char_char(string, pattern, occurrence, consider_overlapping) result(res) character(len=*), intent(in) :: string character(len=*), intent(in) :: pattern integer, intent(in), optional :: occurrence logical, intent(in), optional :: consider_overlapping integer :: lps_array(len(pattern)) integer :: res, s_i, p_i, length_string, length_pattern, occurrence_ occurrence_ = optval(occurrence, 1) res = 0 length_string = len(string) length_pattern = len(pattern) if (length_pattern > 0 .and. length_pattern <= length_string & & .and. occurrence_ > 0) then lps_array = compute_lps(pattern) s_i = 1 p_i = 1 do while(s_i <= length_string) if (string(s_i:s_i) == pattern(p_i:p_i)) then if (p_i == length_pattern) then occurrence_ = occurrence_ - 1 if (occurrence_ == 0) then res = s_i - length_pattern + 1 exit else if (optval(consider_overlapping, .true.)) then p_i = lps_array(p_i) else p_i = 0 end if end if s_i = s_i + 1 p_i = p_i + 1 else if (p_i > 1) then p_i = lps_array(p_i - 1) + 1 else s_i = s_i + 1 end if end do end if end function find_char_char !> Computes longest prefix suffix for each index of the input 'string' !> !> Returns an array of integers pure function compute_lps(string) result(lps_array) character(len=*), intent(in) :: string integer :: lps_array(len(string)) integer :: i, j, length_string length_string = len(string) if (length_string > 0) then lps_array(1) = 0 i = 2 j = 1 do while (i <= length_string) if (string(j:j) == string(i:i)) then lps_array(i) = j i = i + 1 j = j + 1 else if (j > 1) then j = lps_array(j - 1) + 1 else lps_array(i) = 0 i = i + 1 end if end do end if end function compute_lps !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_string_string_string(string, pattern, replacement) result(res) type(string_type), intent(in) :: string type(string_type), intent(in) :: pattern type(string_type), intent(in) :: replacement type(string_type) :: res res = string_type(replace_all(char(string), & & char(pattern), char(replacement))) end function replace_all_string_string_string !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_string_string_char(string, pattern, replacement) result(res) type(string_type), intent(in) :: string type(string_type), intent(in) :: pattern character(len=*), intent(in) :: replacement type(string_type) :: res res = string_type(replace_all(char(string), char(pattern), replacement)) end function replace_all_string_string_char !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_string_char_string(string, pattern, replacement) result(res) type(string_type), intent(in) :: string character(len=*), intent(in) :: pattern type(string_type), intent(in) :: replacement type(string_type) :: res res = string_type(replace_all(char(string), pattern, char(replacement))) end function replace_all_string_char_string !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_char_string_string(string, pattern, replacement) result(res) character(len=*), intent(in) :: string type(string_type), intent(in) :: pattern type(string_type), intent(in) :: replacement character(len=:), allocatable :: res res = replace_all(string, char(pattern), char(replacement)) end function replace_all_char_string_string !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_string_char_char(string, pattern, replacement) result(res) type(string_type), intent(in) :: string character(len=*), intent(in) :: pattern character(len=*), intent(in) :: replacement type(string_type) :: res res = string_type(replace_all(char(string), pattern, replacement)) end function replace_all_string_char_char !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_char_string_char(string, pattern, replacement) result(res) character(len=*), intent(in) :: string type(string_type), intent(in) :: pattern character(len=*), intent(in) :: replacement character(len=:), allocatable :: res res = replace_all(string, char(pattern), replacement) end function replace_all_char_string_char !> Replaces all occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_char_char_string(string, pattern, replacement) result(res) character(len=*), intent(in) :: string character(len=*), intent(in) :: pattern type(string_type), intent(in) :: replacement character(len=:), allocatable :: res res = replace_all(string, pattern, char(replacement)) end function replace_all_char_char_string !> Replaces all the occurrences of substring 'pattern' in the input 'string' !> with the replacement 'replacement' !> Returns a new string pure function replace_all_char_char_char(string, pattern, replacement) result(res) character(len=*), intent(in) :: string character(len=*), intent(in) :: pattern character(len=*), intent(in) :: replacement character(len=:), allocatable :: res integer :: lps_array(len(pattern)) integer :: s_i, p_i, last, length_string, length_pattern res = "" length_string = len(string) length_pattern = len(pattern) last = 1 if (length_pattern > 0 .and. length_pattern <= length_string) then lps_array = compute_lps(pattern) s_i = 1 p_i = 1 do while (s_i <= length_string) if (string(s_i:s_i) == pattern(p_i:p_i)) then if (p_i == length_pattern) then res = res // & & string(last : s_i - length_pattern) // & & replacement last = s_i + 1 p_i = 0 end if s_i = s_i + 1 p_i = p_i + 1 else if (p_i > 1) then p_i = lps_array(p_i - 1) + 1 else s_i = s_i + 1 end if end do end if res = res // string(last : length_string) end function replace_all_char_char_char !> Left pad the input string with " " (1 whitespace) !> !> Returns a new string pure function padl_string_default(string, output_length) result(res) type(string_type), intent(in) :: string integer, intent(in) :: output_length type(string_type) :: res res = string_type(padl(char(string), output_length, " ")) end function padl_string_default !> Left pad the input string with the 'pad_with' character !> !> Returns a new string pure function padl_string_pad_with(string, output_length, pad_with) result(res) type(string_type), intent(in) :: string integer, intent(in) :: output_length character(len=1), intent(in) :: pad_with type(string_type) :: res res = string_type(padl(char(string), output_length, pad_with)) end function padl_string_pad_with !> Left pad the input string with " " (1 whitespace) !> !> Returns a new string pure function padl_char_default(string, output_length) result(res) character(len=*), intent(in) :: string integer, intent(in) :: output_length character(len=max(len(string), output_length)) :: res res = padl(string, output_length, " ") end function padl_char_default !> Left pad the input string with the 'pad_with' character !> !> Returns a new string pure function padl_char_pad_with(string, output_length, pad_with) result(res) character(len=*), intent(in) :: string integer, intent(in) :: output_length character(len=1), intent(in) :: pad_with character(len=max(len(string), output_length)) :: res integer :: string_length string_length = len(string) if (string_length < output_length) then res = repeat(pad_with, output_length - string_length) res(output_length - string_length + 1 : output_length) = string else res = string end if end function padl_char_pad_with !> Right pad the input string with " " (1 whitespace) !> !> Returns a new string pure function padr_string_default(string, output_length) result(res) type(string_type), intent(in) :: string integer, intent(in) :: output_length character(len=max(len(string), output_length)) :: char_output type(string_type) :: res ! We're taking advantage of `char_output` being longer than `string` and ! initialized with whitespaces. By casting `string` to a `character` ! type and back to `string_type`, we're effectively right-padding ! `string` with spaces, so we don't need to pad explicitly. char_output = char(string) res = string_type(char_output) end function padr_string_default !> Right pad the input string with the 'pad_with' character !> !> Returns a new string pure function padr_string_pad_with(string, output_length, pad_with) result(res) type(string_type), intent(in) :: string integer, intent(in) :: output_length character(len=1), intent(in) :: pad_with type(string_type) :: res res = string_type(padr(char(string), output_length, pad_with)) end function padr_string_pad_with !> Right pad the input string with " " (1 whitespace) !> !> Returns a new string pure function padr_char_default(string, output_length) result(res) character(len=*), intent(in) :: string integer, intent(in) :: output_length character(len=max(len(string), output_length)) :: res res = string end function padr_char_default !> Right pad the input string with the 'pad_with' character !> !> Returns a new string pure function padr_char_pad_with(string, output_length, pad_with) result(res) character(len=*), intent(in) :: string integer, intent(in) :: output_length character(len=1), intent(in) :: pad_with character(len=max(len(string), output_length)) :: res integer :: string_length string_length = len(string) res = string if (string_length < output_length) then res(string_length + 1 : output_length) = & repeat(pad_with, output_length - string_length) end if end function padr_char_pad_with !> Returns the number of times substring 'pattern' has appeared in the !> input string 'string' !> Returns an integer elemental function count_string_string(string, pattern, consider_overlapping) result(res) type(string_type), intent(in) :: string type(string_type), intent(in) :: pattern logical, intent(in), optional :: consider_overlapping integer :: res res = count(char(string), char(pattern), consider_overlapping) end function count_string_string !> Returns the number of times substring 'pattern' has appeared in the !> input string 'string' !> Returns an integer elemental function count_string_char(string, pattern, consider_overlapping) result(res) type(string_type), intent(in) :: string character(len=*), intent(in) :: pattern logical, intent(in), optional :: consider_overlapping integer :: res res = count(char(string), pattern, consider_overlapping) end function count_string_char !> Returns the number of times substring 'pattern' has appeared in the !> input string 'string' !> Returns an integer elemental function count_char_string(string, pattern, consider_overlapping) result(res) character(len=*), intent(in) :: string type(string_type), intent(in) :: pattern logical, intent(in), optional :: consider_overlapping integer :: res res = count(string, char(pattern), consider_overlapping) end function count_char_string !> Returns the number of times substring 'pattern' has appeared in the !> input string 'string' !> Returns an integer elemental function count_char_char(string, pattern, consider_overlapping) result(res) character(len=*), intent(in) :: string character(len=*), intent(in) :: pattern logical, intent(in), optional :: consider_overlapping integer :: lps_array(len(pattern)) integer :: res, s_i, p_i, length_string, length_pattern res = 0 length_string = len(string) length_pattern = len(pattern) if (length_pattern > 0 .and. length_pattern <= length_string) then lps_array = compute_lps(pattern) s_i = 1 p_i = 1 do while (s_i <= length_string) if (string(s_i:s_i) == pattern(p_i:p_i)) then if (p_i == length_pattern) then res = res + 1 if (optval(consider_overlapping, .true.)) then p_i = lps_array(p_i) else p_i = 0 end if end if s_i = s_i + 1 p_i = p_i + 1 else if (p_i > 1) then p_i = lps_array(p_i - 1) + 1 else s_i = s_i + 1 end if end do end if end function count_char_char !> Left pad the input string with zeros !> !> Returns a new string pure function zfill_string(string, output_length) result(res) type(string_type), intent(in) :: string integer, intent(in) :: output_length type(string_type) :: res res = string_type(padl(char(string), output_length, "0")) end function zfill_string !> Left pad the input string with zeros !> !> Returns a new string pure function zfill_char(string, output_length) result(res) character(len=*), intent(in) :: string integer, intent(in) :: output_length character(len=max(len(string), output_length)) :: res res = padl(string, output_length, "0") end function zfill_char end module stdlib_strings