Loading...
Searching...
No Matches
string.f90
Go to the documentation of this file.
1!> @file
2!! @defgroup group_string String
3!! Minimal yet powerful variable-length string type with modern Fortran features.
4!! This module implements a lightweight `string` derived type that behaves like
5!! a true variable-length character string while remaining fully compatible with
6!! intrinsic Fortran character operations.
7!!
8!! Features:
9!! - Automatic memory management via `allocatable character(:)`
10!! - Overloaded assignment (`=`) between `string` and `character(*)`
11!! - Overloaded operators: `//` (concatenation), `==` (equality), `.contains.` (membership)
12!! - Generic interfaces for `len`, `len_trim`, `trim`
13!! - Full support for formatted I/O (`write`, `print`)
14!! - Helper routines for parsing Fortran source (line continuation, upper/lower case conversion, etc.)
15!!
16!! The design is intentionally minimal - it provides only what's necessary for
17!! robust string handling in scientific and preprocessing applications,
18!! avoiding the bloat of larger string libraries while remaining fast and standards-compliant.
19!! @note All procedures are `pure` or `elemental` when possible for maximum performance
20!! and usability in array contexts.
21!!
22!! @section string_examples Examples
23!!
24!! @par Basic Usage
25!! @code{.f90}
26!! type(string) :: s, t
27!! character(:), allocatable :: line
28!!
29!! s = 'Hello' ! Assignment from literal
30!! t = s // ' World!' ! Concatenation
31!! print *, t%chars ! Output: Hello World!
32!!
33!! if (s == 'Hello') then
34!! print *, 'Equal'
35!! else
36!! print *, 'Case sensitive'
37!! endif
38!!
39!! print *, len(t) ! -> 12
40!! print *, len_trim(t) ! -> 12
41!! ...
42!! @endcode
43!!
44!! @par Array and Container Support
45!! @code{.f90}
46!! type(string) :: words(3)
47!! logical :: found
48!!
49!! words = [string('apple'), string('banana'), string('cherry')]
50!! found = words .contains. 'banana' ! --> .true.
51!! found = words .contains. string('date') ! --> .false.
52!! ...
53!! @endcode
54!!
55!! @par Advanced: Source Code Processing
56!! @code{.f90}
57!! character(len=:), allocatable :: code_line
58!! code_line = uppercase('program hello_world ! comment') ! --> 'PROGRAM HELLO_WORLD ! comment'
59!! ...
60!! @endcode
61module fpx_string
62 use fpx_constants
63
64 implicit none; private
65
66 public :: len, &
67 len_trim, &
68 trim, &
69 operator(//), &
70 operator(.contains.), &
71 index
72
73 public :: starts_with, &
74 head, &
75 tail, &
76 previous, &
77 concat, &
78 writechk, &
79 uppercase, &
81
82 !> Represents text as a sequence of ASCII code units.
83 !! The derived type wraps an allocatable character array.
84 !!
85 !! @section string_type_examples Examples
86 !!
87 !! @code{.f90}
88 !! type(string) :: s
89 !! s = 'foo'
90 !! @endcode
91 !!
92 !! @section string_type_constructor Constructors
93 !! Initializes a new instance of the string class
94 !! <h3>string(character(:))</h3>
95 !! @verbatim type(string) function string(chars) @endverbatim
96 !!
97 !! @param[in] chars character(:)
98 !!
99 !! @b Examples
100 !! @code{.f90}
101 !! type(string) :: s
102 !! s = string('foo')
103 !! @endcode
104 !! @return The constructed string object.
105 !!
106 !! @section string_type_remarks Remarks
107 !! The string implementation proposed here is kept at the bare
108 !! minimum of what is required by the library. There are many
109 !! other implementations that can be found.
110 !!
111 !! @ingroup group_string
112 type, public :: string
113 character(:), allocatable :: chars !< Variable length character array
114 contains
115 !! @cond
116 procedure, pass(lhs), private :: character_assign_string
117 procedure, pass(rhs), private :: string_assign_character
118 procedure, pass(lhs), private :: string_eq_string !! Equal to string logical operator.
119 procedure, pass(lhs), private :: string_eq_character !! Equal to character logical operator.
120 procedure, pass(rhs), private :: character_eq_string !! Equal to character (inverted) logical operator.
121 procedure, pass(dtv), private :: write_formatted !! Formatted output.
122 !! @endcond
123 generic, public :: assignment(=) => character_assign_string, &
124 string_assign_character
125 generic, public :: operator(==) => string_eq_string, &
126 string_eq_character, &
127 character_eq_string
128 generic, public :: write(formatted) => write_formatted
129 end type
130
131 !> Return the length of a string
132 !!
133 !! @b Remarks
134 !! @ingroup group_string
135 interface len
136 module procedure :: string_len
137 end interface
138
139 !> Return the trimmed length of a string
140 !!
141 !! @b Remarks
142 !! @ingroup group_string
143 interface len_trim
144 module procedure :: string_len_trim
145 end interface
146
147 !> Return the trimmed string
148 !!
149 !! @b Remarks
150 !! @ingroup group_string
151 interface trim
152 module procedure :: string_trim
153 end interface
154
155 !> Concatenation operator
156 !!
157 !! @b Remarks
158 !! @ingroup group_string
159 interface operator(//)
160 module procedure :: string_concat_string
161 module procedure :: string_concat_character
162 module procedure :: character_concat_string
163 end interface
164
165 !> Check whether a string belongs to a list or not
166 !!
167 !! @b Remarks
168 !! @ingroup group_string
169 interface operator(.contains.)
170 module procedure :: strings_contain_string
171 module procedure :: strings_contain_character
172 module procedure :: characters_contain_string
173 module procedure :: characters_contain_character
174 end interface
175
176 !> Index operator
177 !!
178 !! @b Remarks
179 !! @ingroup group_string
180 interface index
181 module procedure :: index_string_string
182 module procedure :: index_string_character
183 module procedure :: index_character_string
184 end interface
185
186contains
187
188 !> Assignment overloading. Assign a character array to a string.
189 !! @param[inout] lhs string
190 !! @param[in] rhs character(*)
191 !!
192 !! @b Examples
193 !! @code{.f90}
194 !! type(string) :: s
195 !!
196 !! s = 'foo'
197 !! @endcode
198 !!
199 !! @b Remarks
200 subroutine character_assign_string(lhs, rhs)
201 class(string), intent(inout) :: lhs
202 character(*), intent(in) :: rhs
203
204 if (allocated(lhs%chars)) deallocate(lhs%chars)
205 allocate(lhs%chars, source=rhs)
206 end subroutine
207
208 !> Assignment overloading. Assign a string to a character array.
209 !! @param[inout] lhs character(:), allocatable
210 !! @param[in] rhs string
211 !!
212 !! @b Examples
213 !! @code{.f90}
214 !! type(string) :: s
215 !! character(:), allocatable :: c
216 !!
217 !! s = 'foo'
218 !! c = s
219 !! ! The value of c is now 'foo'
220 !! @endcode
221 !!
222 !! @b Remarks
223 subroutine string_assign_character(lhs, rhs)
224 character(:), allocatable, intent(inout) :: lhs
225 class(string), intent(in) :: rhs
226
227 lhs = rhs%chars
228 end subroutine
229
230 !> Length of the string entity.
231 !! @param[in] this string
232 !!
233 !! @b Examples
234 !! @code{.f90}
235 !! type(string) :: s
236 !! integer :: l
237 !!
238 !! s = string('foo ')
239 !! l = len(s)
240 !! ! The value of l is 4
241 !! @endcode
242 !! @return An integer corresponding to the length of the string.
243 !!
244 !! @b Remarks
245 elemental integer function string_len(this) result(res)
246 class(string), intent(in) :: this
247
248 if (allocated(this%chars)) then
249 res = len(this%chars)
250 else
251 res = 0
252 end if
253 end function
254
255 !> Length of the string entity without trailing blanks (len_trim).
256 !! @param[in] this string
257 !!
258 !! @b Examples
259 !! @code{.f90}
260 !! type(string) :: s
261 !! integer :: l
262 !!
263 !! s = string('foo ')
264 !! l = len_trim(s)
265 !! ! The value of l is 3
266 !! @endcode
267 !! @return An integer corresponding to the trimmed length of the string.
268 !!
269 !! @b Remarks
270 pure integer function string_len_trim(this) result(res)
271 class(string), intent(in) :: this
272
273 if (allocated(this%chars)) then
274 res = len_trim(this%chars)
275 else
276 res = 0
277 end if
278 end function
279
280 !> Returns a copy of the string with trailing blanks removed.
281 !! @param[in] this string
282 !! @return Trimmed character string (deferred length).
283 !!
284 !! @b Remarks
285 pure function string_trim(this) result(res)
286 class(string), intent(in) :: this
287 character(:), allocatable :: res
288
289 if (allocated(this%chars)) then
290 res = trim(this%chars)
291 else
292 res = ''
293 end if
294 end function
295
296 !> Concatenation of two string objects.
297 !! @param[in] lhs left-hand side string
298 !! @param[in] rhs right-hand side string
299 !! @return New concatenated string.
300 !!
301 !! @b Remarks
302 pure function string_concat_string(lhs, rhs) result(res)
303 class(string), intent(in) :: lhs
304 class(string), intent(in) :: rhs
305 character(:), allocatable :: res
306
307 if (allocated(lhs%chars) .and. allocated(rhs%chars)) then
308 res = lhs%chars // rhs%chars
309 elseif (allocated(lhs%chars)) then
310 res = lhs%chars
311 elseif (allocated(rhs%chars)) then
312 res = rhs%chars
313 else
314 res = ''
315 end if
316 end function
317
318 !> Concatenation of string and character expression.
319 !! @param[in] lhs string
320 !! @param[in] rhs character expression
321 !! @return New concatenated string.
322 !!
323 !! @b Remarks
324 pure function string_concat_character(lhs, rhs) result(res)
325 class(string), intent(in) :: lhs
326 character(*), intent(in) :: rhs
327 character(:), allocatable :: res
328
329 if (allocated(lhs%chars)) then
330 res = lhs%chars // rhs
331 else
332 res = rhs
333 end if
334 end function
335
336 !> Concatenation of character expression and string.
337 !! @param[in] lhs character expression
338 !! @param[in] rhs string
339 !! @return New concatenated string.
340 !!
341 !! @b Remarks
342 pure function character_concat_string(lhs, rhs) result(res)
343 character(*), intent(in) :: lhs
344 class(string), intent(in) :: rhs
345 character(:), allocatable :: res
346
347 if (allocated(rhs%chars)) then
348 res = lhs // rhs%chars
349 else
350 res = lhs
351 end if
352 end function
353
354 !> Equality comparison between two string objects.
355 !! @param[in] lhs left-hand side
356 !! @param[in] rhs right-hand side
357 !! @return .true. if the strings are equal, .false. otherwise.
358 !!
359 !! @b Remarks
360 elemental function string_eq_string(lhs, rhs) result(res)
361 class(string), intent(in) :: lhs !! Left hand side.
362 class(string), intent(in) :: rhs !! Right hand side.
363 logical :: res !! Opreator test result.
364
365 if (.not. allocated(lhs%chars)) then
366 res = allocated(rhs%chars)
367 else
368 res = lhs%chars == rhs%chars
369 end if
370 end function
371
372 !> Equality comparison between string and character expression.
373 !! @param[in] lhs string
374 !! @param[in] rhs character expression
375 !! @return .true. if equal, .false. otherwise.
376 !!
377 !! @b Remarks
378 elemental function string_eq_character(lhs, rhs) result(res)
379 class(string), intent(in) :: lhs !! Left hand side.
380 character(*), intent(in) :: rhs !! Right hand side.
381 logical :: res !! Opreator test result.
382
383 if (.not. allocated(lhs%chars)) then
384 res = .false.
385 else
386 res = lhs%chars == rhs
387 end if
388 end function
389
390 !> Equality comparison (reversed) between character expression and string.
391 !! @param[in] lhs character expression
392 !! @param[in] rhs string
393 !! @return .true. if equal, .false. otherwise.
394 !!
395 !! @b Remarks
396 elemental function character_eq_string(lhs, rhs) result(res)
397 character(*), intent(in) :: lhs !! Left hand side.
398 class(string), intent(in) :: rhs !! Right hand side.
399 logical :: res !! Operator test result.
400
401 if (.not. allocated(rhs%chars)) then
402 res = .false.
403 else
404 res = rhs%chars == lhs
405 end if
406 end function
407
408 !> Formatted output procedure for user-defined type @ref string (UDTIO)
409 !! This procedure is called automatically when a formatted WRITE statement is used
410 !! with a variable of type `string` (when using the DT edit descriptor or default
411 !! formatted output for the type).
412 !!
413 !! It writes the content of the string component `dtv%chars` using a simple `A` format.
414 !! If the string is not allocated, an empty string is written.
415 !!
416 !! @param[in] dtv The @ref string object to be written (polymorphic dummy argument)
417 !! @param[in] unit Fortran logical unit number
418 !! @param[in] iotype String describing the edit descriptor ('DT' + optional string)
419 !! @param[in] v_list Integer array containing the values from the DT edit descriptor
420 !! (v_list is empty if no parentheses were used after DT)
421 !! @param[out] iostat I/O status code (0 = success, positive = error, negative = end-of-file/end-of-record)
422 !! @param[inout] iomsg Message describing the I/O error (if any)
423 !!
424 !! @b Note
425 !! - This implementation **ignores** `iotype` and `v_list` parameters
426 !! -> the same simple character output is always performed
427 !! - The procedure always uses format `(A)`
428 !! - Empty (not allocated) string is written as empty line (zero characters)
429 !!
430 !! @b Warning
431 !! This is a minimal implementation of UDTIO formatted output.
432 !! More sophisticated versions could:
433 !! - respect `iotype` (DT"..." or LISTDIRECTED)
434 !! - use `v_list` for width/precision control
435 !! - add quotation marks, escaping, etc.
436 !!
437 !! @b Examples
438 !! @code{.f90}
439 !! type(string) :: s
440 !! call s%set("Hello formatted world!")
441 !!
442 !! write(*, *) s ! may call write_formatted (depending on compiler)
443 !! write(*, '(DT)') s ! explicitly calls write_formatted
444 !! @endcode
445 !!
446 !! @b Remarks
447 ! allow(assumed-size-character-intent)
448 subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
449 class(string), intent(in) :: dtv
450 integer, intent(in) :: unit !! Logical unit.
451 character(*), intent(in) :: iotype !! Edit descriptor.
452 integer, intent(in) :: v_list(:) !! Edit descriptor list.
453 integer, intent(out) :: iostat !! IO status code.
454 character(*), intent(inout) :: iomsg !! IO status message.
455
456 if (allocated(dtv%chars)) then
457 write(unit, '(A)', iostat=iostat, iomsg=iomsg) dtv%chars
458 else
459 write(unit, '(A)', iostat=iostat, iomsg=iomsg) ''
460 end if
461 end subroutine
462
463 !> Checks if a string starts with a given prefix
464 !! Returns `.true.` if the string `str` (after trimming leading/trailing whitespace)
465 !! begins exactly with the substring `arg1`.
466 !! The function uses `index()` after trimming both strings with `trim(adjustl())`.
467 !!
468 !! @param[in] str The string to be tested
469 !! @param[in] arg1 The prefix to look for at the beginning of `str`
470 !! @param[out] idx (optional) If present, receives the starting position of `arg1` in the trimmed string
471 !! (will be 1 if the function returns `.true.`, otherwise >1 or 0)
472 !!
473 !! @return `.true.` if `str` starts with `arg1` (after trimming), `.false.` otherwise
474 !!
475 !! @b Note
476 !! - Leading and trailing whitespace of both `str` and `arg1` is ignored
477 !! - Comparison is case-sensitive
478 !! - Empty `arg1` will always return `.true.` (any string starts with empty string)
479 !!
480 !! @b Warning
481 !! The returned index (when requested) is the position **after trimming** of the input string,
482 !! not in the original untrimmed string.
483 !!
484 !! @b Examples
485 !! @code{.f90}
486 !! character(80) :: line = ' hello world '
487 !! logical :: ok
488 !! integer :: pos
489 !!
490 !! ok = starts_with(line, 'hello') ! -> .true.
491 !! ok = starts_with(line, 'hello', pos) ! -> .true. and pos = 1
492 !! ok = starts_with(line, 'world') ! -> .false.
493 !! ok = starts_with(' test123 ', 'test') ! -> .true.
494 !! ...
495 !! @endcode
496 !!
497 !! @b Remarks
498 !! @ingroup group_string
499 logical function starts_with(str, arg1, idx) result(res)
500 character(*), intent(in) :: str
501 character(*), intent(in) :: arg1
502 integer, intent(out), optional :: idx
503 !private
504 integer :: i
505
506 i = index(trim(adjustl(str)), trim(arg1))
507 res = (i == 1)
508 if (present(idx)) idx = i
509 end function
510
511 !> Returns the first non-blank character of a string.
512 !! @param[in] str input string
513 !! @return First character (space if empty)
514 !!
515 !! @b Remarks
516 !! @ingroup group_string
517 character function head(str) result(res)
518 character(*), intent(in) :: str
519
520 res = ' '
521 if (len_trim(str) == 0) return
522
523 res = str(1:1)
524 end function
525
526 !> Returns the last non-blank character of a string.
527 !! @param[in] str input string
528 !! @return Last character (space if empty)
529 !!
530 !! @b Remarks
531 !! @ingroup group_string
532 character function tail(str) result(res)
533 character(*), intent(in) :: str
534 !private
535 integer :: n
536
537 res = ' '; n = len_trim(str)
538 if (n == 0) return
539
540 res = str(n:n)
541 end function
542
543 !> Smart concatenation that removes continuation markers (&) and handles line-continuation rules.
544 !! @param[in] str1 first line
545 !! @param[in] str2 second line
546 !! @return Concatenated string with proper continuation handling
547 !!
548 !! @b Remarks
549 !! @ingroup group_string
550 function concat(str1, str2) result(res)
551 character(*), intent(in) :: str1
552 character(*), intent(in) :: str2
553 character(:), allocatable :: res
554 !private
555 integer :: n1, n2
556
557 n1 = len(str1); n2 = 1
558 if (head(str1) == '!') then
559 n2 = 2
560 if (tail(str1) == '&') n1 = len_trim(str1) - 1
561 if (starts_with(str2, '!dir$') .or. starts_with(str2, '!DIR$') .or. &
562 starts_with(str2, '!dec$') .or. starts_with(str2, '!DEC$') .or. &
563 starts_with(str2, '!gcc$') .or. starts_with(str2, '!GCC$') .or. &
564 starts_with(str2, '!acc$') .or. starts_with(str2, '!ACC$') .or. &
565 starts_with(str2, '!$omp') .or. starts_with(str2, '!$OMP')) then
566 n2 = 6
567 end if
568 if (head(adjustl(str2(n2:))) == '&') then
569 n2 = index(str2, '&') + 1
570 end if
571 else
572 if (tail(str1) == '&') n1 = len_trim(str1) - 1
573 if (head(trim(str2)) == '&') n2 = index(str2, '&') + 1
574 if (tail(str1(:n1)) == '(') n1 = index(str1(:n1), '(', back=.true.)
575 end if
576
577 if (len(str1) > 0 .and. len(str2) >= n2) then
578 if (str1(n1:n1) == ' ' .and. str2(n2:n2) == ' ') n2 = n2 + 1
579 end if
580 res = str1(:n1) // str2(n2:)
581 end function
582
583 !> Convert string to upper case (respects contents of quotes).
584 !! @param[in] str input string
585 !! @return Upper-case version of the string
586 !!
587 !! @b Examples
588 !! @code
589 !! character(*), parameter :: input = 'test'
590 !! character(:), allocatable :: output
591 !! output = uppercase(input)
592 !! if (output == 'TEST') print*, 'OK'
593 !! @endcode
594 !!
595 !! @b Remarks
596 !! @ingroup group_string
597 pure function uppercase(str) result(res)
598 character(*), intent(in) :: str
599 character(len_trim(str)) :: res
600 !private
601 integer :: ilen, ioffset, iquote, iqc, iav, i
602
603 ilen = len_trim(str)
604 ioffset = iachar('A') - iachar('a')
605 iquote = 0
606 res = str
607 do i = 1, ilen
608 iav = iachar(str(i:i))
609 if (iquote == 0 .and. (iav == 34 .or. iav == 39)) then
610 iquote = 1
611 iqc = iav
612 cycle
613 end if
614 if (iquote == 1 .and. iav == iqc) then
615 iquote = 0
616 cycle
617 end if
618 if (iquote == 1) cycle
619 if (iav >= iachar('a') .and. iav <= iachar('z')) then
620 res(i:i) = achar(iav + ioffset)
621 else
622 res(i:i) = str(i:i)
623 end if
624 end do
625 end function
626
627 !> Convert string to lower case (respects contents of quotes).
628 !! @param[in] str input string
629 !! @return Lower-case version of the string
630 !!
631 !! @b Examples
632 !! @code
633 !! character(*), parameter :: input = 'TEST'
634 !! character(:), allocatable :: output
635 !! output = lowercase(input)
636 !! if (output == 'test') print*, 'OK'
637 !! @endcode
638 !!
639 !! @b Remarks
640 !! @ingroup group_string
641 pure function lowercase(str) result(res)
642 character(*), intent(in) :: str
643 character(len_trim(str)) :: res
644 !private
645 integer :: ilen, ioffset, iquote, iqc, iav, i
646
647 ilen = len_trim(str)
648 ioffset = iachar('A') - iachar('a')
649 iquote = 0
650 res = str
651 do i = 1, ilen
652 iav = iachar(str(i:i))
653 if (iquote == 0 .and. (iav == 34 .or. iav == 39)) then
654 iquote = 1
655 iqc = iav
656 cycle
657 end if
658 if (iquote == 1 .and. iav == iqc) then
659 iquote = 0
660 cycle
661 end if
662 if (iquote == 1) cycle
663 if (iav >= iachar('A') .and. iav <= iachar('Z')) then
664 res(i:i) = achar(iav - ioffset)
665 else
666 res(i:i) = str(i:i)
667 end if
668 end do
669 end function
670
671 !> Write a long line split into chunks of size CHKSIZE with continuation (&).
672 !! @param[in] unit logical unit
673 !! @param[in] str string to write
674 !!
675 !! @b Remarks
676 !! @ingroup group_string
677 subroutine writechk(unit, str)
678 integer, intent(in) :: unit
679 character(*), intent(in) :: str
680 !private
681 integer :: i, n
682
683 n = 0
684 if (head(str) /= '!') then
685 n = floor(len(str) / real(chksize))
686 do i = 1, n
687 write(unit, '(A)') str((i - 1) * chksize + 1:i * chksize) // '&'
688 end do
689 end if
690 write(unit, '(A)') str(n * chksize + 1:)
691 end subroutine
692
693 !> Returns the previous non-blank character before position pos (updates pos).
694 !! @param[in] line input line
695 !! @param[inout] pos current position (moved backward)
696 !! @return Previous non-blank character
697 !!
698 !! @b Remarks
699 !! @ingroup group_string
700 character(1) function previous(line, pos) result(res)
701 character(*), intent(in) :: line
702 integer, intent(inout) :: pos
703 !private
704
705 if (pos == 1) then
706 res = trim(line(pos:pos))
707 else
708 do while (line(pos:pos) == ' ')
709 pos = pos - 1
710 if (pos == 1) exit
711 end do
712 res = line(pos:pos)
713 end if
714 end function
715
716 !> Checks whether an array of string contains a given string.
717 !! @param[in] lhs array of string
718 !! @param[in] rhs string to search for
719 !! @return .true. if rhs is present in lhs
720 !!
721 !! @b Remarks
722 logical function strings_contain_string(lhs, rhs) result(res)
723 type(string), intent(in) :: lhs(:)
724 type(string), intent(in) :: rhs
725 !private
726 integer :: i
727
728 res = .false.
729 do i = 1, size(lhs)
730 if (lhs(i) == rhs) then
731 res = .true.
732 exit
733 end if
734 end do
735 end function
736
737 !> Checks whether an array of string contains a given character expression.
738 !! @param[in] lhs array of string
739 !! @param[in] rhs character expression to search for
740 !! @return .true. if rhs is present in lhs
741 !!
742 !! @b Remarks
743 logical function strings_contain_character(lhs, rhs) result(res)
744 type(string), intent(in) :: lhs(:)
745 character(*), intent(in) :: rhs
746 !private
747 integer :: i
748
749 res = .false.
750 do i = 1, size(lhs)
751 if (lhs(i) == rhs) then
752 res = .true.
753 exit
754 end if
755 end do
756 end function
757
758 !> Checks whether an array of character contains a given character expression.
759 !! @param[in] lhs array of character
760 !! @param[in] rhs character expression to search for
761 !! @return .true. if rhs is present in lhs
762 !!
763 !! @b Remarks
764 logical function characters_contain_character(lhs, rhs) result(res)
765 character(*), intent(in) :: lhs(:)
766 character(*), intent(in) :: rhs
767 !private
768 integer :: i
769
770 res = .false.
771 do i = 1, size(lhs)
772 if (lhs(i) == rhs) then
773 res = .true.
774 exit
775 end if
776 end do
777 end function
778
779 !> Checks whether an array of character contains a given string.
780 !! @param[in] lhs array of character
781 !! @param[in] rhs string to search for
782 !! @return .true. if rhs is present in lhs
783 !!
784 !! @b Remarks
785 logical function characters_contain_string(lhs, rhs) result(res)
786 character(*), intent(in) :: lhs(:)
787 type(string), intent(in) :: rhs
788 !private
789 integer :: i
790
791 res = .false.
792 do i = 1, size(lhs)
793 if (lhs(i) == rhs) then
794 res = .true.
795 exit
796 end if
797 end do
798 end function
799
800 integer function index_string_string(str, substr, back) result(res)
801 class(string), intent(in) :: str
802 class(string), intent(in) :: substr
803 logical, intent(in), optional :: back
804
805 res = index(str%chars, substr%chars, back=back)
806 end function
807
808 integer function index_character_string(str, substr, back) result(res)
809 character(*), intent(in) :: str
810 class(string), intent(in) :: substr
811 logical, intent(in), optional :: back
812
813 res = index(str, substr%chars, back=back)
814 end function
815
816 integer function index_string_character(str, substr, back) result(res)
817 class(string), intent(in) :: str
818 character(*), intent(in) :: substr
819 logical, intent(in), optional :: back
820
821 res = index(str%chars, substr, back=back)
822 end function
823
824end module
integer, parameter, public chksize
Maximum chunk size.
Definition constants.f90:35
character function, public tail(str)
Returns the last non-blank character of a string.
Definition string.f90:533
pure character(len_trim(str)) function, public lowercase(str)
Convert string to lower case (respects contents of quotes).
Definition string.f90:642
subroutine, public writechk(unit, str)
Write a long line split into chunks of size CHKSIZE with continuation (&).
Definition string.f90:678
character(1) function, public previous(line, pos)
Returns the previous non-blank character before position pos (updates pos).
Definition string.f90:701
pure character(len_trim(str)) function, public uppercase(str)
Convert string to upper case (respects contents of quotes).
Definition string.f90:598
character(:) function, allocatable, public concat(str1, str2)
Smart concatenation that removes continuation markers (&) and handles line-continuation rules.
Definition string.f90:551
logical function, public starts_with(str, arg1, idx)
Checks if a string starts with a given prefix Returns .true. if the string str (after trimming leadin...
Definition string.f90:500
character function, public head(str)
Returns the first non-blank character of a string.
Definition string.f90:518
Index operator.
Definition string.f90:180
Return the trimmed length of a string.
Definition string.f90:143
Return the length of a string.
Definition string.f90:135
Return the trimmed string.
Definition string.f90:151
Represents text as a sequence of ASCII code units. The derived type wraps an allocatable character ar...
Definition string.f90:112