Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
fstring.F90
Go to the documentation of this file.
1module fstring
2
3 use iso_c_binding, only : c_int, c_long_long, c_float, c_double, c_bool, &
4 c_short, c_null_char
5 implicit none
6
7 private
8
9 public :: operator(+)
10 interface operator(+)
11 procedure :: concatenate_char_char_fn
12 procedure :: concatenate_char_int_fn
13 procedure :: concatenate_char_float_fn
14 procedure :: concatenate_char_double_fn
15 end interface operator(+)
16
17 ! interface assignment(=)
18 ! procedure :: integer_to_char_sub
19 ! procedure :: float_to_char_sub
20 ! procedure :: double_to_char_sub
21 ! end interface assignment(=)
22
23 public :: operator( .strequal. )
24 interface operator( .strequal. )
25 procedure :: is_char_equal_to_char_case_sensitive_fn
26 end interface operator( .strequal. )
27
28 public :: operator( .strapprox. )
29 interface operator( .strapprox. )
30 procedure :: is_char_equal_to_char_case_insensitive_fn
31 end interface operator( .strapprox. )
32
33 public :: operator( .contains. )
34 interface operator( .contains. )
35 procedure :: is_string2_present_in_string1_case_sensitive_fn
36 end interface operator( .contains. )
37
38 public :: operator( .containssimilar. )
39 interface operator( .containssimilar. )
40 procedure :: is_string2_present_in_string1_case_insensitive_fn
41 end interface operator( .containssimilar. )
42
43 public :: ascharacter
44 interface ascharacter
45 procedure :: short_to_char_fn
46 procedure :: int_to_char_fn
47 procedure :: long_long_to_char_fn
48 procedure :: float_to_char_fn
49 procedure :: double_to_char_fn
50 procedure :: bool_to_char_fn
51 end interface ascharacter
52
53
54 public :: as_character
55 interface as_character
56 procedure :: short_to_char_fn
57 procedure :: int_to_char_fn
58 procedure :: long_long_to_char_fn
59 procedure :: float_to_char_fn
60 procedure :: double_to_char_fn
61 procedure :: bool_to_char_fn
62 end interface as_character
63
64 public :: as_integer
65 interface as_integer
66 procedure :: string_to_integer_fn
67 end interface as_integer
68
69 public :: as_float
70 interface as_float
71 procedure :: string_to_float_fn
72 end interface as_float
73
74 public :: chomp
75 interface chomp
76 procedure :: split_and_return_text_sub
77 end interface chomp
78
79 public :: fieldcount
80 interface fieldcount
81 procedure :: count_number_of_fields_fn
82 end interface fieldcount
83
84 public :: clean
85 interface clean
86 procedure :: remove_multiple_characters_fn
87 end interface clean
88
89 public :: squote
90 interface squote
91 procedure :: squote_char_fn
92 end interface squote
93
94 public :: dquote
95 interface dquote
96 procedure :: dquote_char_fn
97 end interface dquote
98
99 public :: replace
100 interface replace
101 procedure :: replace_character_sub
102 end interface replace
103
104 public :: asuppercase
105 interface asuppercase
106 procedure :: char_to_uppercase_fn
107 end interface asuppercase
108
109 public :: aslowercase
110 interface aslowercase
111 procedure :: char_to_lowercase_fn
112 end interface aslowercase
113
114 public :: touppercase
115 interface touppercase
116 procedure :: char_to_uppercase_sub
117 end interface touppercase
118
119 public :: tolowercase
120 interface tolowercase
121 procedure :: char_to_lowercase_sub
122 end interface tolowercase
123
124 public :: as_uppercase
125 interface as_uppercase
126 procedure :: char_to_uppercase_fn
127 end interface as_uppercase
128
129 public :: as_lowercase
130 interface as_lowercase
131 procedure :: char_to_lowercase_fn
132 end interface as_lowercase
133
134 public :: to_uppercase
135 interface to_uppercase
136 procedure :: char_to_uppercase_sub
137 end interface to_uppercase
138
139 public :: to_lowercase
140 interface to_lowercase
141 procedure :: char_to_lowercase_sub
142 end interface to_lowercase
143
144 public :: right
145 interface right
146 procedure :: return_right_part_of_string_fn
147 end interface right
148
149 public :: left
150 interface left
151 procedure :: return_left_part_of_string_fn
152 end interface left
153
154 public :: f_to_c_str
155 interface f_to_c_str
156 procedure :: f_to_c_string_fn
157 end interface f_to_c_str
158
159 public :: c_to_f_str
160 interface c_to_f_str
161 procedure :: c_to_f_string_fn
162 end interface c_to_f_str
163
164 ! [ special ASCII characters ]
167 character (len=1), parameter :: tab = achar(9)
168 character (len=2), parameter :: whitespace = " "//achar(9)
169 character (len=1), parameter :: backslash = achar(92)
170 character (len=1), parameter :: forwardslash = achar(47)
171 character (len=1), parameter :: carriage_return = achar(13)
172 character (len=3), parameter :: comment_characters = "#!%"
173 character (len=1), parameter :: double_quote = achar(34)
174 character (len=3), parameter :: punctuation = ",;:"
175
176 private :: na_int, na_float, na_double
177 integer (c_int), parameter :: na_int = - (huge(1_c_int)-1_c_int)
178 real (c_float), parameter :: na_float = - (huge(1._c_float)-1._c_float)
179 real (c_double), parameter :: na_double = - (huge(1._c_double)-1._c_double)
180
181contains
182
183
184 impure elemental function string_to_integer_fn(text) result(value)
185
186 character (len=*), intent(in) :: text
187 integer (c_int) :: value
188
189 ! [ LOCALS ]
190 integer (c_int) :: op_status
191 character (len=:), allocatable :: temp_str
192 real (c_float) :: float_value
193
194 ! Try raw input first — handles clean integers and trailing non-numeric text
195 read(unit=text, fmt=*, iostat=op_status) value
196 if (op_status == 0) return
197
198 ! Fallback: strip non-numeric characters and retry
199 temp_str = keepnumeric(text)
200
201 ! if the cleaned up string appears to be a real value,
202 ! attempt to read as real and convert to int
203 if ( scan(temp_str, ".") /= 0 ) then
204
205 read(unit=temp_str, fmt=*, iostat=op_status) float_value
206 if (op_status == 0) value = int(float_value, c_int)
207
208 else
209
210 read(unit=temp_str, fmt=*, iostat=op_status) value
211
212 endif
213
214 if (op_status /= 0) value = na_int
215
216 end function string_to_integer_fn
217
218!--------------------------------------------------------------------------------------------------
219
220 impure elemental function string_to_float_fn(text) result(value)
221
222 character (len=*), intent(in) :: text
223 real (c_float) :: value
224
225 ! [ LOCALS ]
226 integer (c_int) :: op_status
227 character (len=:), allocatable :: temp_str
228
229 ! Try raw input first — handles scientific notation and trailing units
230 read(unit=text, fmt=*, iostat=op_status) value
231 if (op_status == 0) return
232
233 ! Fallback: strip non-numeric characters and retry
234 temp_str = keepnumeric(text)
235 read(unit=temp_str, fmt=*, iostat=op_status) value
236 if (op_status /= 0) value = na_float
237
238 end function string_to_float_fn
239
240!--------------------------------------------------------------------------------------------------
241
242 function return_left_part_of_string_fn( string, indx, substring ) result( left_part )
243
244 character (len=*), intent(in) :: string
245 integer (c_int), intent(in), optional :: indx
246 character (len=*), intent(in), optional :: substring
247 character (len=:), allocatable :: left_part
248
249 ! [ LOCALS ]
250 integer (c_int) :: position
251
252 if ( present( indx ) ) then
253
254 if ( ( indx > 0 ) .and. ( indx < len_trim( string ) ) ) then
255
256 left_part = string( 1:indx )
257
258 else
259
260 left_part = "<NA>"
261
262 endif
263
264 elseif ( present( substring ) ) then
265
266 position = index( string, substring )
267
268 if ( position > 0 ) then
269
270 left_part = string( 1:(position-1) )
271
272 else
273
274 left_part = "<NA>"
275
276 endif
277
278 else
279
280 left_part = "<NA>"
281
282 endif
283
284
286
287!--------------------------------------------------------------------------------------------------
288
289 function return_right_part_of_string_fn( string, indx, substring ) result( right_part )
290
291 character (len=*), intent(in) :: string
292 integer (c_int), intent(in), optional :: indx
293 character (len=*), intent(in), optional :: substring
294 character (len=:), allocatable :: right_part
295
296 ! [ LOCALS ]
297 integer (c_int) :: position
298
299 if ( present( indx ) ) then
300
301 if ( ( indx > 0 ) .and. ( indx < len_trim( string ) ) ) then
302
303 right_part = string( (indx+1):len_trim(string) )
304
305 else
306
307 right_part = "<NA>"
308
309 endif
310
311 elseif ( present( substring ) ) then
312
313 position = index( string, substring, back=.true._c_bool )
314
315 if ( position > 0 ) then
316
317 right_part = string( (position+1):len_trim(string) )
318
319 else
320
321 right_part = "<NA>"
322
323 endif
324
325 else
326
327 right_part = "<NA>"
328
329 endif
330
331
333
334 !--------------------------------------------------------------------------------------------------
335
336 pure function is_string2_present_in_string1_case_insensitive_fn(sText1, sText2) result(lBool)
337
338 character (len=*), intent(in) :: stext1
339 character (len=*), intent(in) :: stext2
340 logical (c_bool) :: lbool
341
342 ! [ LOCALS ]
343 character (len=len_trim(sText1)) :: stemp1
344 character (len=len_trim(sText2)) :: stemp2
345
346 lbool = .false._c_bool
347
348 stemp1 = asuppercase(stext1)
349 stemp2 = asuppercase(stext2)
350
351 if ( index(stemp1, stemp2) /= 0 ) lbool = .true._c_bool
352
354
355 !--------------------------------------------------------------------------------------------------
356
357 pure function is_string2_present_in_string1_case_sensitive_fn(sText1, sText2) result(lBool)
358
359 character (len=*), intent(in) :: stext1
360 character (len=*), intent(in) :: stext2
361 logical (c_bool) :: lbool
362
363 ! [ LOCALS ]
364 character (len=len_trim(sText1)) :: stemp1
365 character (len=len_trim(sText2)) :: stemp2
366
367 lbool = .false._c_bool
368
369 stemp1 = trim( stext1 )
370 stemp2 = trim( stext2 )
371
372 if ( index(stemp1, stemp2) /= 0 ) lbool = .true._c_bool
373
375
376 !--------------------------------------------------------------------------------------------------
377
378 pure function is_char_equal_to_char_case_sensitive_fn(sText1, sText2) result(lBool)
379
380 character (len=*), intent(in) :: stext1
381 character (len=*), intent(in) :: stext2
382 logical (c_bool) :: lbool
383
384 ! [ LOCALS ]
385 character (len=:), allocatable :: stemp1
386 character (len=:), allocatable :: stemp2
387
388 lbool = .false._c_bool
389
390 stemp1 = trim( stext1 )
391 stemp2 = trim( stext2 )
392
393 if (trim(adjustl( stemp1 ) ) .eq. trim(adjustl( stemp2) ) ) lbool = .true._c_bool
394
396
397 !--------------------------------------------------------------------------------------------------
398
399 pure function is_char_equal_to_char_case_insensitive_fn(sText1, sText2) result(lBool)
400
401 character (len=*), intent(in) :: stext1
402 character (len=*), intent(in) :: stext2
403 logical (c_bool) :: lbool
404
405 ! [ LOCALS ]
406 character (len=:), allocatable :: stemp1
407 character (len=:), allocatable :: stemp2
408
409 lbool = .false._c_bool
410
411 stemp1 = asuppercase( stext1 )
412 stemp2 = asuppercase( stext2 )
413
414 if (trim(adjustl( stemp1 ) ) .eq. trim(adjustl( stemp2) ) ) lbool = .true._c_bool
415
417
418 !--------------------------------------------------------------------------------------------------
419
420 function concatenate_char_char_fn(sText1, sText2) result(sText)
421
422 character (len=*), intent(in) :: stext1
423 character (len=*), intent(in) :: stext2
424 character (len=:), allocatable :: stext
425
426 stext = stext1 // stext2
427
428 end function concatenate_char_char_fn
429
430 !--------------------------------------------------------------------------------------------------
431
432 function concatenate_char_int_fn(sText1, iValue1) result(sText)
433
434 character (len=*), intent(in) :: stext1
435 integer (c_int), intent(in) :: ivalue1
436 character (len=:), allocatable :: stext
437
438 stext = stext1 // ascharacter( ivalue1 )
439
440 end function concatenate_char_int_fn
441
442 !--------------------------------------------------------------------------------------------------
443
444 function concatenate_char_float_fn(sText1, fValue1) result(sText)
445
446 character (len=*), intent(in) :: stext1
447 real (c_float), intent(in) :: fvalue1
448 character (len=:), allocatable :: stext
449
450 stext = stext1 // ascharacter( fvalue1 )
451
452 end function concatenate_char_float_fn
453
454 !--------------------------------------------------------------------------------------------------
455
456 function concatenate_char_double_fn(sText1, dValue1) result(sText)
457
458 character (len=*), intent(in) :: stext1
459 real (c_double), intent(in) :: dvalue1
460 character (len=:), allocatable :: stext
461
462 stext = stext1 // ascharacter( dvalue1 )
463
464 end function concatenate_char_double_fn
465
466 !--------------------------------------------------------------------------------------------------
467 function short_to_char_fn(value, fmt_string) result(text)
468 integer (c_short), intent(in) :: value
469 character (len=*), intent(in), optional :: fmt_string
470 character (len=:), allocatable :: text
471
472 integer (c_int) :: status
473 character (len=32) :: sbuf
474
475 if ( present(fmt_string) ) then
476 write(sbuf, fmt="("//trim(fmt_string)//")", iostat=status) value
477 else
478 write(sbuf, fmt=*, iostat=status) value
479 endif
480
481 if (status==0) then
482 text = trim( adjustl(sbuf) )
483 else
484 text = "<NA>"
485 endif
486
487 end function short_to_char_fn
488
489!--------------------------------------------------------------------------------------------------
490
491 function int_to_char_fn(value, fmt_string) result(text)
492 integer (c_int), intent(in) :: value
493 character (len=*), intent(in), optional :: fmt_string
494 character (len=:), allocatable :: text
495
496 integer (c_int) :: status
497 character (len=32) :: sbuf
498
499 if ( present(fmt_string) ) then
500 write(sbuf, fmt="("//trim(fmt_string)//")", iostat=status) value
501 else
502 write(sbuf, fmt=*, iostat=status) value
503 endif
504
505 if (status==0) then
506 text = trim( adjustl(sbuf) )
507 else
508 text = "<NA>"
509 endif
510
511 end function int_to_char_fn
512
513!--------------------------------------------------------------------------------------------------
514
515 function long_long_to_char_fn(value, fmt_string) result(text)
516 integer (c_long_long), intent(in) :: value
517 character (len=*), intent(in), optional :: fmt_string
518 character (len=:), allocatable :: text
519
520 integer (c_int) :: status
521 character (len=32) :: sbuf
522
523 if ( present(fmt_string) ) then
524 write(sbuf, fmt="("//trim(fmt_string)//")", iostat=status) value
525 else
526 write(sbuf, fmt=*, iostat=status) value
527 endif
528
529 if (status==0) then
530 text = trim( adjustl(sbuf) )
531 else
532 text = "<NA>"
533 endif
534
535 end function long_long_to_char_fn
536
537!--------------------------------------------------------------------------------------------------
538
539 function float_to_char_fn(value, fmt_string) result(text)
540 real (c_float), intent(in) :: value
541 character (len=*), intent(in), optional :: fmt_string
542 character (len=:), allocatable :: text
543
544 integer (c_int) :: status
545 character (len=32) :: sbuf
546
547 if ( present(fmt_string) ) then
548 write(sbuf, fmt="("//trim(fmt_string)//")", iostat=status) value
549 else
550 write(sbuf, fmt=*, iostat=status) value
551 endif
552
553 if (status==0) then
554 text = trim( adjustl(sbuf) )
555 else
556 text = "<NA>"
557 endif
558
559 end function float_to_char_fn
560
561!--------------------------------------------------------------------------------------------------
562
563 function double_to_char_fn(value, fmt_string) result(text)
564 real (c_double), intent(in) :: value
565 character (len=*), intent(in), optional :: fmt_string
566 character (len=:), allocatable :: text
567
568 integer (c_int) :: status
569 character (len=32) :: sbuf
570
571 if ( present(fmt_string) ) then
572 write(sbuf, fmt="("//trim(fmt_string)//")", iostat=status) value
573 else
574 write(sbuf, fmt=*, iostat=status) value
575 endif
576
577 if (status==0) then
578 text = trim( adjustl(sbuf) )
579 else
580 text = "<NA>"
581 endif
582
583 end function double_to_char_fn
584
585!--------------------------------------------------------------------------------------------------
586
587 function bool_to_char_fn(value) result(text)
588 logical (c_bool), intent(in) :: value
589 character (len=:), allocatable :: text
590
591
592 if ( value ) then
593 text = ".TRUE._c_bool"
594 else
595 text = "False"
596 endif
597
598 end function bool_to_char_fn
599
600!--------------------------------------------------------------------------------------------------
601
602 function squote_char_fn(sText1) result(sText)
603
604 character (len=*), intent(in) :: stext1
605 character (len=:), allocatable :: stext
606
607 stext = "'"//trim(stext1)//"'"
608
609 end function squote_char_fn
610
611!--------------------------------------------------------------------------------------------------
612
613 function dquote_char_fn(sText1) result(sText)
614
615 character (len=*), intent(in) :: stext1
616 character (len=:), allocatable :: stext
617
618 stext = '"'//trim(stext1)//'"'
619
620 end function dquote_char_fn
621
622 !--------------------------------------------------------------------------------------------------
623
624 pure function char_to_uppercase_fn ( s ) result(sText)
625
626 ! ARGUMENTS
627 character (len=*), intent(in) :: s
628 character(len=len(s)) :: stext
629
630 ! LOCALS
631 integer (c_int) :: i ! do loop index
632
633 ! CONSTANTS
634 integer (c_int), parameter :: lower_to_upper = -32
635 integer (c_int), parameter :: ascii_small_a = ichar("a")
636 integer (c_int), parameter :: ascii_small_z = ichar("z")
637
638 stext = s
639
640 do i=1,len_trim(stext)
641 if ( ichar(stext(i:i) ) >= ascii_small_a .and. ichar(stext(i:i)) <= ascii_small_z ) then
642 stext(i:i) = char( ichar( stext(i:i) ) + lower_to_upper )
643 end if
644 end do
645
646 end function char_to_uppercase_fn
647
648 !--------------------------------------------------------------------------
649
650 pure function char_to_lowercase_fn ( s ) result(sText)
651
652 ! ARGUMENTS
653 character (len=*), intent(in) :: s
654 character(len=len(s)) :: stext
655
656 ! LOCALS
657 integer (c_int) :: i ! do loop index
658 ! CONSTANTS
659 integer (c_int), parameter :: upper_to_lower = 32
660 integer (c_int), parameter :: ascii_a = ichar("A")
661 integer (c_int), parameter :: ascii_z = ichar("Z")
662
663 stext = s
664
665 do i=1,len_trim(stext)
666 if ( ichar(stext(i:i) ) >= ascii_a .and. ichar(stext(i:i)) <= ascii_z ) then
667 stext(i:i) = char( ichar( stext(i:i) ) + upper_to_lower )
668 end if
669 end do
670
671 end function char_to_lowercase_fn
672
673
674 subroutine char_to_uppercase_sub ( s )
675
676 ! ARGUMENTS
677 character (len=*), intent(inout) :: s
678 ! LOCALS
679 integer (c_int) :: i ! do loop index
680 ! CONSTANTS
681 integer (c_int), parameter :: LOWER_TO_UPPER = -32
682 integer (c_int), parameter :: ASCII_SMALL_A = ichar("a")
683 integer (c_int), parameter :: ASCII_SMALL_Z = ichar("z")
684
685 do i=1,len_trim(s)
686 if ( ichar(s(i:i) ) >= ascii_small_a .and. ichar(s(i:i)) <= ascii_small_z ) then
687 s(i:i) = char( ichar( s(i:i) ) + lower_to_upper )
688 end if
689 end do
690
691 end subroutine char_to_uppercase_sub
692
693
694 subroutine char_to_lowercase_sub ( s )
695
696 ! ARGUMENTS
697 character (len=*), intent(inout) :: s
698 ! LOCALS
699 integer (c_int) :: i ! do loop index
700 ! CONSTANTS
701 integer (c_int), parameter :: UPPER_TO_LOWER = 32
702 integer (c_int), parameter :: ASCII_A = ichar("A")
703 integer (c_int), parameter :: ASCII_Z = ichar("Z")
704
705 ! UPPER_TO_LOWER = ichar( "a" ) - ichar( "A" )
706
707 do i=1,len_trim( s )
708 if ( ichar(s(i:i) ) >= ascii_a .and. ichar(s(i:i)) <= ascii_z ) then
709 s(i:i) = char( ichar( s(i:i) ) + upper_to_lower )
710 end if
711 end do
712
713 end subroutine char_to_lowercase_sub
714
715
716
717
718
719 !--------------------------------------------------------------------------
720
721
722 !> Strip offending characters from a text string.
723 !!
724 !! Remove unwanted characters from a text string. The target characters may optionally be supplied.
725 !! @param[in] sTextIn
726 impure function remove_multiple_characters_fn(sText1, sTargetCharacters) result(sText)
727
728 ! ARGUMENTS
729 character (len=*), intent(inout) :: stext1
730 character (len=*), intent(in), optional :: stargetcharacters
731 character (len=:), allocatable :: stext
732
733 ! LOCALS
734 character (len=512) :: sbuf
735 integer (c_int) :: ir ! Index in sRecord
736 integer (c_int) :: iindex1, iindex2
737 character (len=:), allocatable :: stargetcharacters_l
738
739 ! eliminate any leading spaces
740 stext1 = adjustl(stext1)
741 sbuf = ""
742 iindex2 = 0
743
744 if (present(stargetcharacters) ) then
745 stargetcharacters_l = stargetcharacters
746 else
747 stargetcharacters_l = ":/;,"
748 endif
749
750 do iindex1 = 1,len_trim(stext1)
751
752 ir = scan(stext1(iindex1:iindex1), stargetcharacters_l)
753
754 if(ir==0) then
755 iindex2 = iindex2 + 1
756 sbuf(iindex2:iindex2) = stext1(iindex1:iindex1)
757 end if
758
759 enddo
760
761 stext = trim(sbuf)
762
764
765 !--------------------------------------------------------------------------------------------------
766
767 function count_number_of_fields_fn( sText, sDelimiters ) result( iCount )
768
769 character (len=*), intent(in) :: stext
770 character (len=*), intent(in), optional :: sdelimiters
771 integer (c_int) :: icount
772
773 ! [ LOCALS ]
774 character (len=len(sText)) :: str
775 character (len=len(sText)) :: substr
776 character (len=:), allocatable :: delimiter_chr_
777
778 if ( present(sdelimiters) ) then
779 delimiter_chr_=sdelimiters
780 else
781 delimiter_chr_ = whitespace
782 endif
783
784 icount = 0
785
786 str = stext
787
788 do
789 call chomp(str=str, substr=substr, delimiter_chr=delimiter_chr_ )
790
791 if ( len_trim( substr ) == 0 ) exit
792
793 icount = icount + 1
794
795 enddo
796
797 end function count_number_of_fields_fn
798
799 !--------------------------------------------------------------------------------------------------
800
801 subroutine split_and_return_text_sub(str, substr, delimiter_chr, remove_extra_delimiters)
802
803 character (len=*), intent(inout) :: str
804 character (len=*), intent(out) :: substr
805 character (len=*), intent(in), optional :: delimiter_chr
806 logical (c_bool), intent(in), optional :: remove_extra_delimiters
807
808 ! [ LOCALS ]
809 character (len=:), allocatable :: delimiter_chr_
810 logical (c_bool) :: remove_extra_delimiters_
811 integer (kind=c_int) :: iIndex
812 integer (c_int) :: n
813
814 if ( present(remove_extra_delimiters)) then
815 remove_extra_delimiters_ = remove_extra_delimiters
816 else
817 remove_extra_delimiters_ = .false._c_bool
818 endif
819
820 if ( present(delimiter_chr) ) then
821 select case (delimiter_chr)
822 case ("WHITESPACE")
823 delimiter_chr_ = whitespace
824 case ("TAB", "TABS")
825 delimiter_chr_ = tab
826 case ("COMMA", "CSV")
827 delimiter_chr_ = ","
828 case default
829 delimiter_chr_ = delimiter_chr
830 end select
831 else
832 delimiter_chr_ = whitespace
833 endif
834
835 str = adjustl(str)
836
837 iindex = scan( string = str, set = delimiter_chr_ )
838
839 if (iindex == 0) then
840 ! no delimiters found; return string as was supplied originally
841 substr = str
842 str = ""
843 else
844 ! delimiters were found; split and return the chunks of text
845 substr = trim( str(1:iindex-1) )
846 str = trim( str(iindex + 1: ) )
847 ! inelegant, but something like this is needed to detect the presence of duplicate delimiters in cases where
848 ! more than one delimiter in a row should just be ignored
849 if (remove_extra_delimiters_) then
850 do
851 n = len_trim(str)
852 if (n == 0 ) exit
853 ! if we still have delimiters (whitespace, for example) in the first position, lop it off and try again
854 if ( scan( string=str(1:1), set=delimiter_chr_) == 0) exit
855 str = trim(str(2:n))
856 enddo
857 endif
858 endif
859
860 end subroutine split_and_return_text_sub
861
862 !--------------------------------------------------------------------------------------------------
863
864 subroutine replace_character_sub(sText1, sFind, sReplace)
865
866 character (len=*), intent(inout) :: sText1
867 character (len=1), intent(in) :: sFind
868 character (len=1), intent(in), optional :: sReplace
869
870 ! [ LOCALS ]
871 integer (c_int) :: iIndex
872 integer (c_int) :: iCount
873 character (len=len_trim(sText1)) :: sText
874
875 stext = ""
876
877 if ( len(stext1) > 0 ) then
878
879 icount = 0
880 do iindex = 1, len_trim(stext1)
881 if ( stext1(iindex:iindex) .ne. sfind) then
882 icount = icount + 1
883 stext(icount:icount) = stext1(iindex:iindex)
884 else
885 if (present(sreplace)) then
886 icount = icount + 1
887 stext(icount:icount) = sreplace
888 endif
889 endif
890 enddo
891
892 endif
893
894 stext1 = trim(stext)
895
896 end subroutine replace_character_sub
897
898!--------------------------------------------------------------------------------------------------
899
900 impure elemental function keepnumeric(text) result(result_text)
901
902 ! ARGUMENTS
903 character (len=*), intent(in) :: text
904 character (len=len(text)) :: result_text
905
906 character (len=:), allocatable :: temp_str
907 character (len=512) :: temp_result
908
909 integer (c_int) :: n
910 integer (c_int) :: index1, index2
911 character (len=:), allocatable :: target_characters
912
913 ! target_character omits the period ("."): do not want a real value returned
914 ! as a funky integer (e.g. string "3.141" returned as integer 3141 )
915 target_characters = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM" &
916 //"!@#$%^&*()_+-={}[]|\:;'<,>?/~`'"//double_quote
917
918 temp_str = adjustl(text)
919 temp_result = ""
920 index2 = 0
921
922 do index1 = 1,len_trim(text)
923 n = scan(text(index1:index1), target_characters)
924 if(n==0) then
925 index2 = index2 + 1
926 temp_result(index2:index2) = text(index1:index1)
927 endif
928 enddo
929
930 result_text = trim(temp_result)
931
932 end function keepnumeric
933
934!--------------------------------------------------------------------------------------------------
935
936 function c_to_f_string_fn(c_character_str) result(f_character_str)
937
938 character (len=*), intent(in) :: c_character_str
939 character (len=:), allocatable :: f_character_str
940
941 integer (c_int) :: indx
942
943 f_character_str = c_character_str
944
945 do indx=1,len(c_character_str)
946 if (c_character_str(indx:indx) == c_null_char) then
947 f_character_str = c_character_str(1:indx-1)
948 exit
949 endif
950 enddo
951
952 end function c_to_f_string_fn
953
954!--------------------------------------------------------------------------------------------------
955
956 function f_to_c_string_fn(f_character_str) result(c_character_str)
957
958 character (len=*), intent(in) :: f_character_str
959 character (len=:), allocatable :: c_character_str
960
961 integer (c_int) :: str_len
962
963 str_len = len_trim(f_character_str)
964
965 if ( str_len == 0 ) then
966 c_character_str = c_null_char
967 elseif ( f_character_str(str_len:str_len) == c_null_char ) then
968 ! already has a null character at end; do not append another
969 c_character_str = trim(f_character_str)
970 else
971 ! last char is not null character; append c_null_char
972 c_character_str = trim(f_character_str)//c_null_char
973 endif
974
975 end function f_to_c_string_fn
976
977
978end module fstring
character(len=1), parameter, public forwardslash
Definition fstring.F90:170
impure elemental integer(c_int) function string_to_integer_fn(text)
Definition fstring.F90:185
character(len=:) function, allocatable int_to_char_fn(value, fmt_string)
Definition fstring.F90:492
character(len=:) function, allocatable dquote_char_fn(stext1)
Definition fstring.F90:614
pure logical(c_bool) function is_string2_present_in_string1_case_insensitive_fn(stext1, stext2)
Definition fstring.F90:337
impure character(len=:) function, allocatable remove_multiple_characters_fn(stext1, stargetcharacters)
Strip offending characters from a text string.
Definition fstring.F90:727
character(len=:) function, allocatable long_long_to_char_fn(value, fmt_string)
Definition fstring.F90:516
subroutine split_and_return_text_sub(str, substr, delimiter_chr, remove_extra_delimiters)
Definition fstring.F90:802
character(len=:) function, allocatable return_left_part_of_string_fn(string, indx, substring)
Definition fstring.F90:243
character(len=:) function, allocatable f_to_c_string_fn(f_character_str)
Definition fstring.F90:957
integer(c_int), parameter, private na_int
Definition fstring.F90:177
character(len=:) function, allocatable concatenate_char_double_fn(stext1, dvalue1)
Definition fstring.F90:457
real(c_double), parameter, private na_double
Definition fstring.F90:179
character(len=:) function, allocatable short_to_char_fn(value, fmt_string)
Definition fstring.F90:468
character(len=3), parameter, public punctuation
Definition fstring.F90:174
character(len=:) function, allocatable squote_char_fn(stext1)
Definition fstring.F90:603
impure elemental real(c_float) function string_to_float_fn(text)
Definition fstring.F90:221
character(len=1), parameter, public carriage_return
Definition fstring.F90:171
character(len=1), parameter, public tab
Definition fstring.F90:167
character(len=:) function, allocatable concatenate_char_float_fn(stext1, fvalue1)
Definition fstring.F90:445
pure character(len=len(s)) function char_to_uppercase_fn(s)
Definition fstring.F90:625
character(len=:) function, allocatable float_to_char_fn(value, fmt_string)
Definition fstring.F90:540
character(len=:) function, allocatable bool_to_char_fn(value)
Definition fstring.F90:588
character(len=:) function, allocatable double_to_char_fn(value, fmt_string)
Definition fstring.F90:564
subroutine char_to_lowercase_sub(s)
Definition fstring.F90:695
character(len=1), parameter, public backslash
Definition fstring.F90:169
subroutine replace_character_sub(stext1, sfind, sreplace)
Definition fstring.F90:865
integer(c_int) function count_number_of_fields_fn(stext, sdelimiters)
Definition fstring.F90:768
pure character(len=len(s)) function char_to_lowercase_fn(s)
Definition fstring.F90:651
impure elemental character(len=len(text)) function keepnumeric(text)
Definition fstring.F90:901
character(len=2), parameter, public whitespace
Definition fstring.F90:168
real(c_float), parameter, private na_float
Definition fstring.F90:178
pure logical(c_bool) function is_string2_present_in_string1_case_sensitive_fn(stext1, stext2)
Definition fstring.F90:358
pure logical(c_bool) function is_char_equal_to_char_case_sensitive_fn(stext1, stext2)
Definition fstring.F90:379
character(len=:) function, allocatable concatenate_char_int_fn(stext1, ivalue1)
Definition fstring.F90:433
subroutine char_to_uppercase_sub(s)
Definition fstring.F90:675
character(len=:) function, allocatable c_to_f_string_fn(c_character_str)
Definition fstring.F90:937
character(len=1), parameter, public double_quote
Definition fstring.F90:173
character(len=:) function, allocatable concatenate_char_char_fn(stext1, stext2)
Definition fstring.F90:421
pure logical(c_bool) function is_char_equal_to_char_case_insensitive_fn(stext1, stext2)
Definition fstring.F90:400
character(len=3), parameter, public comment_characters
Definition fstring.F90:172
character(len=:) function, allocatable return_right_part_of_string_fn(string, indx, substring)
Definition fstring.F90:290