Soil Water Balance (SWB2)
Loading...
Searching...
No Matches
fstring_list.F90
Go to the documentation of this file.
2
3 use iso_c_binding
4 use fstring
5 implicit none
6
7 private
8
9 public :: fstring_list_t
10
11 ! public :: operator(+)
12 ! interface operator(+)
13 ! module procedure :: concatenate_fstring_to_fstring_sub
14 ! end interface operator(+)
15 !
16 public :: assignment(=)
17 interface assignment(=)
18 module procedure :: assign_fstring_to_character_sub
19 end interface assignment(=)
20
22
23 character (len=:), allocatable :: s
24 integer (c_int) :: count = 0
25 integer (c_int) :: missing_value_count = 0
26
27 contains
28
30 generic :: assignment(=) => assign_character_to_fstring_sub
31
33 generic :: print_all => print_all_entries_sub
34
36 generic :: print => print_as_markdown_sub
37
41 generic :: append => append_character_to_fstring_sub, &
44
46 generic :: count_entries => count_strings_in_list_fn
47
52
54 generic :: get_integer => retrieve_values_as_integer_fn
55
57 generic :: get_float => retrieve_values_as_float_fn
58
60 generic :: get_double => retrieve_values_as_double_fn
61
63 generic :: get_logical => retrieve_values_as_logical_fn
64
67
68 procedure :: list_all_fn
69 generic :: list_all => list_all_fn
70
72 generic :: empty_entries_present => are_there_missing_list_values_fn
73
75 generic :: sort => quicksort_alpha_sub
76
77 procedure :: quicksort_int_sub
78 generic :: sort_integer => quicksort_int_sub
79
81 generic :: sort_float => quicksort_float_sub
82
83 procedure :: clear_list_sub
84 generic :: clear => clear_list_sub
85
87 generic :: count_matching => return_count_of_matching_strings_fn
88
89! procedure :: is_substring_present_in_string_case_sensitive_fn
90! procedure :: is_substring_present_in_string_case_insensitive_fn
91
94
97
100
101 end type fstring_list_t
102
103 public :: na_int, na_float, na_double
104 integer (c_int), parameter :: na_int = - (huge(1_c_int)-1_c_int)
105 real (c_float), parameter :: na_float = - (huge(1._c_float)-1._c_float)
106 real (c_double), parameter :: na_double = - (huge(1._c_double)-1._c_double)
107
108 public::split
109 interface split
110 module procedure :: split_character_into_fstring_list_fn
111 end interface split
112
113 public::create_list
114 interface create_list
115 module procedure :: split_character_into_fstring_list_fn
116 end interface create_list
117
119 integer (c_int) :: order
120 character (len=:), allocatable :: alpha_value
121 end type alpha_sort_group_t
122
124 integer (c_int) :: order
125 integer (c_int) :: int_value
126 end type int_sort_group_t
127
129 integer (c_int) :: order
130 real (c_float) :: float_value
131 end type float_sort_group_t
132
133contains
134
135!--------------------------------------------------------------------------------------------------
136
137 subroutine assign_character_to_fstring_sub(this, character_str)
138
139 class(fstring_list_t), intent(inout) :: this
140 character (len=*), intent(in) :: character_str
141
142 call this%clear()
143
144 this%s = f_to_c_str(character_str)
145 this%count = 1
146
148
149!--------------------------------------------------------------------------------------------------
150
151 subroutine assign_fstring_to_character_sub( character_str, string_list )
152
153 character (len=:), allocatable, intent(out) :: character_str
154 type (FSTRING_LIST_T), intent(in) :: string_list
155
156 character (len=:), allocatable :: temp_str
157
158 temp_str = string_list%get(1)
159 character_str = trim(temp_str)
160
162
163!--------------------------------------------------------------------------------------------------
164
165 function split_character_into_fstring_list_fn(character_str, delimiter_chr) result(new_fstring)
166
167 character (len=*), intent(in) :: character_str
168 character (len=1), intent(in), optional :: delimiter_chr
169 type (fstring_list_t) :: new_fstring
170
171 character (len=len(character_str)) :: string
172 character (len=len(character_str)) :: substring
173 character (len=1) :: delimiter_chr_
174 integer (c_int) :: num_delimiters
175 integer (c_int) :: i
176
177 if ( present(delimiter_chr) ) then
178 delimiter_chr_ = delimiter_chr
179 else
180 delimiter_chr_ = ","
181 endif
182
183 string = character_str
184 num_delimiters = 0
185
186 do i=1, len_trim(string)
187 if ( string(i:i) == delimiter_chr_ ) num_delimiters = num_delimiters + 1
188 enddo
189
190 if ( num_delimiters == 0 ) then
191
192 else
193
194! example: "one, two, three, four"
195! num_delimiters=3
196
197 do i=1, num_delimiters
198 call chomp(string, substring, delimiter_chr_)
199 call new_fstring%append( substring )
200 end do
201
202 call chomp(string, substring, delimiter_chr_)
203 call new_fstring%append( substring )
204
205 endif
206
208
209!--------------------------------------------------------------------------------------------------
210
211 function count_strings_in_list_fn(this) result(count)
212
213 class(fstring_list_t), intent(inout), target :: this
214 integer (c_int) :: count
215
216 integer (c_int) :: i
217
218 count = 0
219
220 do i=1, len_trim(this%s)
221 if( this%s(i:i) == c_null_char ) count = count + 1
222 enddo
223
224 end function count_strings_in_list_fn
225
226!--------------------------------------------------------------------------------------------------
227
228 subroutine append_character_to_fstring_sub(this, character_str)
229
230 class(fstring_list_t), intent(inout), target :: this
231 character (len=*), intent(in) :: character_str
232
233 if ( .not. allocated( this%s ) ) this%s = ""
234 this%s = trim(this%s)//trim(adjustl(f_to_c_str(character_str)))
235 if ( len_trim(character_str) == 0 ) &
236 this%missing_value_count = this%missing_value_count + 1
237 this%count = this%count + 1
238
240
241!--------------------------------------------------------------------------------------------------
242
243subroutine append_character_array_to_fstring_sub(this, character_str)
244
245 class(fstring_list_t), intent(inout), target :: this
246 character (len=*), intent(in) :: character_str(:)
247
248 integer (c_int) :: i
249
250 do i=1, size(character_str,1)
251
252 this%s = trim(this%s)//trim(adjustl(f_to_c_str(character_str(i))))
253 if ( len_trim(character_str(i)) == 0 ) &
254 this%missing_value_count = this%missing_value_count + 1
255 this%count = this%count + 1
256
257 enddo
258
260
261!--------------------------------------------------------------------------------------------------
262
263subroutine append_fstring_to_fstring_sub(this, other_fstring)
264
265 class(fstring_list_t), intent(inout), target :: this
266 type (FSTRING_LIST_T), intent(inout) :: other_fstring
267
268 integer (c_int) :: i
269 character (len=:), allocatable :: temp_str
270
271 do i=1, other_fstring%count
272
273 temp_str = other_fstring%get(i)
274 call this%append( other_fstring%get(i) )
275 if ( len_trim(temp_str) == 0 ) &
276 this%missing_value_count = this%missing_value_count + 1
277
278 enddo
279
281
282!--------------------------------------------------------------------------------------------------
283
284 function are_there_missing_list_values_fn(this) result(value)
285
286 class(fstring_list_t), intent(inout), target :: this
287 logical (c_bool) :: value
288
289 if ( this%missing_value_count > 0 ) then
290 value = .true._c_bool
291 else
292 value = .false._c_bool
293 endif
294
296
297!--------------------------------------------------------------------------------------------------
298
299 subroutine print_all_entries_sub(this)
300
301 class(fstring_list_t), intent(inout), target :: this
302
303 character (len=:), allocatable :: sbuf
304 integer (c_int) :: start_pos
305 integer (c_int) :: end_pos
306 integer (c_int) :: str_len
307 integer (c_int) :: i
308
309 start_pos = 1
310 end_pos = index( this%s, c_null_char ) - 1
311 str_len = len_trim( this%s )
312
313 do i=1, this%count_entries()
314
315 write(*,fmt="(a)") this%s(start_pos:end_pos)
316
317 start_pos = end_pos + 2
318 end_pos = index( this%s(start_pos:str_len), c_null_char ) + start_pos - 2
319
320 end do
321
322 end subroutine print_all_entries_sub
323
324!--------------------------------------------------------------------------------------------------
325
326 subroutine list_finalize_sub(this)
327
328 type (FSTRING_LIST_T), intent(inout) :: this
329
330 call this%clear()
331
332 end subroutine list_finalize_sub
333
334!--------------------------------------------------------------------------------------------------
335
336 subroutine clear_list_sub(this)
337
338 class(fstring_list_t), intent(inout) :: this
339
340 this%s = ""
341 this%count = 0
342
343 end subroutine clear_list_sub
344
345!--------------------------------------------------------------------------------------------------
346
347 function retrieve_values_as_integer_fn(this) result(values)
348
349 class(fstring_list_t), intent(inout), target :: this
350 integer (c_int), allocatable :: values(:)
351
352 integer (c_int) :: i
353 integer (c_int) :: value
354 integer (c_int) :: op_status
355 character (len=64) :: sbuf
356
357 if (this%count <= 0) then
358 allocate(values(1),stat=op_status)
359 values = na_int
360 else
361
362 allocate(values(this%count),stat=op_status)
363
364 do i=1,this%count
365 sbuf = this%get(i)
366 value = as_integer(sbuf)
367 if ( op_status==0 ) then
368 values(i) = value
369 else
370 values(i) = na_int
371 endif
372 enddo
373
374 endif
375
377
378!--------------------------------------------------------------------------------------------------
379
380 function retrieve_values_as_float_fn(this) result(values)
381
382 class(fstring_list_t), intent(inout), target :: this
383 real (c_float), allocatable :: values(:)
384
385 integer (c_int) :: i
386 real (c_float) :: value
387 integer (c_int) :: op_status
388 character (len=64) :: sbuf
389
390 if (this%count <= 0) then
391 allocate(values(1),stat=op_status)
392 values = na_float
393 else
394 allocate(values(this%count),stat=op_status)
395
396 do i=1,this%count
397 sbuf = this%get(i)
398 read(unit=sbuf, fmt=*, iostat=op_status) value
399 if ( op_status==0 ) then
400 values(i) = value
401 else
402 values(i) = na_float
403 endif
404 enddo
405
406 endif
407
408 end function retrieve_values_as_float_fn
409
410!--------------------------------------------------------------------------------------------------
411
412function retrieve_values_as_double_fn(this) result(values)
413
414 class(fstring_list_t), intent(inout), target :: this
415 real (c_double), allocatable :: values(:)
416
417 integer (c_int) :: i
418 real (c_double) :: value
419 integer (c_int) :: op_status
420 character (len=64) :: sbuf
421
422 if (this%count <=0) then
423
424 allocate(values(1),stat=op_status)
425 values = na_double
426
427 else
428
429 allocate(values(this%count),stat=op_status)
430
431 do i=1,this%count
432 sbuf = this%get(i)
433 read(unit=sbuf, fmt=*, iostat=op_status) value
434 if ( op_status==0 ) then
435 values(i) = value
436 else
437 values(i) = na_double
438 endif
439 enddo
440
441 endif
442
444
445!--------------------------------------------------------------------------------------------------
446
447function retrieve_values_as_logical_fn(this) result(values)
448
449 class(fstring_list_t), intent(inout) :: this
450 logical (c_bool), allocatable :: values(:)
451
452 integer (c_int) :: i
453 logical (c_bool) :: value
454 integer (c_int) :: op_status
455 character (len=64) :: sbuf
456
457 allocate(values(this%count),stat=op_status)
458
459 do i=1,this%count
460 sbuf = this%get(i)
461
462 select case(sbuf)
463
464 case("true","T","True","TRUE","1","Y","Yes","yes","YES")
465 values(i) = .true._c_bool
466 case default
467 values(i) = .false._c_bool
468
469 end select
470
471 enddo
472
474
475!--------------------------------------------------------------------------------------------------
476
477 function retrieve_value_from_list_at_index_fn(this, index_val) result(text)
478
479 class(fstring_list_t), intent(in) :: this
480 integer (c_int), intent(in) :: index_val
481 character(len=:), allocatable :: text
482
483 integer (c_int) :: start_pos
484 integer (c_int) :: end_pos
485 integer (c_int) :: str_len
486 integer (c_int) :: i
487
488 start_pos = 1
489 text = "<NA>"
490
491 if ( allocated(this%s) ) then
492
493 end_pos = index( this%s, c_null_char ) - 1
494 str_len = len_trim( this%s )
495
496 do i=1, this%count
497
498 if ( index_val == i ) then
499 text = this%s(start_pos:end_pos)
500 exit
501 endif
502
503 ! skip over the 'c_null_char' to position of beginning of
504 ! next substring
505 start_pos = end_pos + 2
506 end_pos = index( this%s(start_pos:str_len), c_null_char ) + start_pos - 2
507
508 end do
509
510 endif
511
513
514!--------------------------------------------------------------------------------------------------
515
516 subroutine replace_value_at_index_sub(this, index_val, character_str)
517
518 class(fstring_list_t), intent(inout) :: this
519 integer (c_int), intent(in) :: index_val
520 character(len=*) :: character_str
521
522 integer (c_int) :: i
523 type (FSTRING_LIST_T) :: temp_list
524
525
526 if (this%count > 0) then
527
528 do i=1, this%count
529 if ( index_val == i ) then
530 call temp_list%append(character_str)
531 else
532 call temp_list%append(this%get(i))
533 endif
534 end do
535
536 this%s = temp_list%s
537
538 endif
539
540 end subroutine replace_value_at_index_sub
541
542!--------------------------------------------------------------------------------------------------
543
544 function retrieve_values_for_range_of_indices_fn(this, start_indx, end_indx) result(text)
545
546 class(fstring_list_t), intent(inout) :: this
547 integer (c_int), intent(in) :: start_indx
548 integer (c_int), intent(in) :: end_indx
549 character (len=:), allocatable :: text
550
551 integer (c_int) :: i
552
553 if (this%count == 0) then
554 text = "<NA>"
555 else
556 do i=1, this%count
557 if (i == start_indx) then
558 text = trim(this%get(i))
559 elseif (i > start_indx .and. i <= end_indx ) then
560 text = trim(text)//" "//trim(this%get(i))
561 endif
562 enddo
563 endif
564
566
567!--------------------------------------------------------------------------------------------------
568
569 function list_all_fn(this, delimiter_chr) result( text )
570
571 class(fstring_list_t), intent(inout) :: this
572 character (len=1), intent(in), optional :: delimiter_chr
573 character (len=:), allocatable :: text
574
575 integer (c_int) :: i
576
577 if (this%count == 0) then
578 text = "<NA>"
579 elseif (present(delimiter_chr) ) then
580 text = trim(this%get(1))
581 do i=2, this%count
582 text = trim(text)//delimiter_chr//trim(this%get(i))
583 enddo
584 else
585 text = "(1) "//trim(this%get(1))
586 do i=2, this%count
587 text = trim(text)//" ("//as_character(i)//") "//trim(this%get(i))
588 enddo
589 endif
590
591 end function list_all_fn
592
593!--------------------------------------------------------------------------------------------------
594
595 subroutine quicksort_alpha_sub(this, sort_order)
596
597 class(fstring_list_t), intent(inout) :: this
598 character (len=*), intent(in), optional :: sort_order
599
600 type (ALPHA_SORT_GROUP_T), allocatable :: sort_group(:)
601 integer (c_int) :: i
602 integer (c_int) :: count
603 logical (c_bool) :: decreasing_order
604
605 decreasing_order = .false._c_bool
606
607 if ( present(sort_order) ) then
608 select case (sort_order)
609
610 case ("Decreasing","decreasing","DECREASING")
611 decreasing_order = .true._c_bool
612 end select
613 endif
614
615 count = this%count
616
617 allocate(sort_group(count))
618
619 ! create the 'sort_group' data structure
620 do i=1, count
621 sort_group(i)%order = i
622 sort_group(i)%alpha_value = this%get(i)
623 enddo
624
625 call qsort_alpha(sort_group, this%count)
626
627 ! wipe out previous values
628 call this%clear()
629
630 if ( decreasing_order ) then
631 ! copy sorted values back into list structure (DECREASING ORDER)
632 do i=count, 1, -1
633 call this%append(sort_group(i)%alpha_value)
634 enddo
635 else
636 ! copy sorted values back into list structure (INCREASING ORDER)
637 do i=1, count
638 call this%append(sort_group(i)%alpha_value)
639 enddo
640 endif
641
642 end subroutine quicksort_alpha_sub
643
644!-------------------------------------------------------------------------------------------------
645
646 subroutine quicksort_int_sub(this, sort_order)
647 class(fstring_list_t), intent(inout) :: this
648 character (len=*), intent(in), optional :: sort_order
649
650 type (INT_SORT_GROUP_T), allocatable :: sort_group(:)
651 integer (c_int), allocatable :: int_values(:)
652 integer (c_int) :: i
653 integer (c_int) :: count
654 logical (c_bool) :: decreasing_order
655
656 decreasing_order = .false._c_bool
657
658 if ( present(sort_order) ) then
659 select case (sort_order)
660 case ("Decreasing","decreasing","DECREASING")
661 decreasing_order = .true._c_bool
662 end select
663 endif
664
665 count = this%count
666
667 allocate(sort_group(count))
668 allocate(int_values(count))
669
670 int_values = this%get_integer()
671
672 ! create the 'sort_group' data structure
673 do i=1, count
674 sort_group(i)%order = i
675 sort_group(i)%int_value = int_values(i)
676 enddo
677
678 call qsort_int(sort_group, this%count)
679 ! wipe out previous values
680 call this%clear()
681 if ( decreasing_order ) then
682 ! copy sorted values back into list structure (DECREASING ORDER)
683 do i=count, 1, -1
684 call this%append( as_character(sort_group(i)%int_value) )
685 enddo
686 else
687 ! copy sorted values back into list structure (INCREASING ORDER)
688 do i=1, count
689 call this%append( as_character(sort_group(i)%int_value) )
690 enddo
691 endif
692 end subroutine quicksort_int_sub
693
694!-------------------------------------------------------------------------------------------------
695
696 subroutine quicksort_float_sub(this, sort_order)
697
698 class(fstring_list_t), intent(inout) :: this
699 character (len=*), intent(in), optional :: sort_order
700
701 type (FLOAT_SORT_GROUP_T), allocatable :: sort_group(:)
702 real (c_float), allocatable :: float_values(:)
703 integer (c_int) :: i
704 integer (c_int) :: count
705 logical (c_bool) :: decreasing_order
706
707 decreasing_order = .false._c_bool
708
709 if ( present(sort_order) ) then
710 select case (sort_order)
711
712 case ("Decreasing","decreasing","DECREASING")
713 decreasing_order = .true._c_bool
714 end select
715 endif
716
717 count = this%count
718
719 allocate(sort_group(count))
720
721 float_values = this%get_float()
722
723 ! create the 'sort_group' data structure
724 do i=1, count
725 sort_group(i)%order = i
726 sort_group(i)%float_value = float_values(i)
727 enddo
728
729 call qsort_float(sort_group, this%count)
730
731 ! wipe out previous values
732 call this%clear()
733
734 if ( decreasing_order ) then
735 ! copy sorted values back into list structure (DECREASING ORDER)
736 do i=count, 1, -1
737 call this%append( as_character(sort_group(i)%float_value) )
738 enddo
739 else
740 ! copy sorted values back into list structure (INCREASING ORDER)
741 do i=1, count
742 call this%append( as_character(sort_group(i)%float_value) )
743 enddo
744 endif
745
746 end subroutine quicksort_float_sub
747
748!-------------------------------------------------------------------------------------------------
749
750 recursive subroutine qsort_alpha(sort_group, nrec)
751
752 ! NOTE: this code based on code found here:
753 ! https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran
754
755 ! DUMMY ARGUMENTS
756 type (alpha_sort_group_t), dimension(nrec), intent(in out) :: sort_group
757 integer (c_int), intent(in) :: nrec
758
759 ! LOCAL VARIABLES
760 integer (c_int) :: left, right
761 real (c_float) :: random
762 character (len=:), allocatable :: pivot
763 type (alpha_sort_group_t) :: temp
764 integer (c_int) :: marker
765
766 if (nrec > 1) then
767
768 call random_number(random)
769 pivot = sort_group(int(random*real(nrec-1))+1)%alpha_value ! random pivor (not best performance, but avoids worst-case)
770 left = 0
771 right = nrec + 1
772
773 do while (left < right)
774 right = right - 1
775 do while (sort_group(right)%alpha_value > pivot)
776 right = right - 1
777 end do
778 left = left + 1
779 do while (sort_group(left)%alpha_value < pivot)
780 left = left + 1
781 end do
782 if (left < right) then
783 temp = sort_group(left)
784 sort_group(left) = sort_group(right)
785 sort_group(right) = temp
786 end if
787 end do
788
789 if (left == right) then
790 marker = left + 1
791 else
792 marker = left
793 end if
794
795 call qsort_alpha(sort_group(:marker-1),marker-1)
796 call qsort_alpha(sort_group(marker:),nrec-marker+1)
797
798 end if
799
800 end subroutine qsort_alpha
801
802!--------------------------------------------------------------------------------------------------
803
804 recursive subroutine qsort_int(sort_group, nrec)
805
806 ! NOTE: this code based on code found here:
807 ! https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran
808
809 ! DUMMY ARGUMENTS
810 type (int_sort_group_t), dimension(nrec), intent(in out) :: sort_group
811 integer (c_int), intent(in) :: nrec
812
813 ! LOCAL VARIABLES
814 integer (c_int) :: left, right
815 real (c_float) :: random
816 integer (c_int) :: pivot
817 type (int_sort_group_t) :: temp
818 integer (c_int) :: marker
819
820 if (nrec > 1) then
821
822 call random_number(random)
823 pivot = sort_group(int(random*real(nrec-1))+1)%int_value ! random pivor (not best performance, but avoids worst-case)
824 left = 0
825 right = nrec + 1
826
827 do while (left < right)
828 right = right - 1
829 do while (sort_group(right)%int_value > pivot)
830 right = right - 1
831 end do
832 left = left + 1
833 do while (sort_group(left)%int_value < pivot)
834 left = left + 1
835 end do
836 if (left < right) then
837 temp = sort_group(left)
838 sort_group(left) = sort_group(right)
839 sort_group(right) = temp
840 end if
841 end do
842
843 if (left == right) then
844 marker = left + 1
845 else
846 marker = left
847 end if
848
849 call qsort_int(sort_group(:marker-1),marker-1)
850 call qsort_int(sort_group(marker:),nrec-marker+1)
851
852 end if
853
854 end subroutine qsort_int
855
856!--------------------------------------------------------------------------------------------------
857
858 recursive subroutine qsort_float(sort_group, nrec)
859
860 ! NOTE: this code based on code found here:
861 ! https://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran
862
863 ! DUMMY ARGUMENTS
864 type (float_sort_group_t), dimension(nrec), intent(in out) :: sort_group
865 integer (c_int), intent(in) :: nrec
866
867 ! LOCAL VARIABLES
868 integer (c_int) :: left, right
869 real (c_float) :: random
870 real (c_float) :: pivot
871 type (float_sort_group_t) :: temp
872 integer (c_int) :: marker
873
874 if (nrec > 1) then
875
876 call random_number(random)
877 pivot = sort_group(int(random*real(nrec-1))+1)%float_value ! random pivor (not best performance, but avoids worst-case)
878 left = 0
879 right = nrec + 1
880
881 do while (left < right)
882 right = right - 1
883 do while (sort_group(right)%float_value > pivot)
884 right = right - 1
885 end do
886 left = left + 1
887 do while (sort_group(left)%float_value < pivot)
888 left = left + 1
889 end do
890 if (left < right) then
891 temp = sort_group(left)
892 sort_group(left) = sort_group(right)
893 sort_group(right) = temp
894 end if
895 end do
896
897 if (left == right) then
898 marker = left + 1
899 else
900 marker = left
901 end if
902
903 call qsort_float(sort_group(:marker-1),marker-1)
904 call qsort_float(sort_group(marker:),nrec-marker+1)
905
906 end if
907
908 end subroutine qsort_float
909
910!--------------------------------------------------------------------------------------------------
911
912 function return_count_of_matching_strings_fn(this, substr, match_case) result(count)
913
914 class(fstring_list_t), intent(inout) :: this
915 character (len=*), intent(in) :: substr
916
917 logical (c_bool), intent(in), optional :: match_case
918 integer (c_int) :: count
919
920 ! [ LOCALS ]
921 integer (c_int) :: i
922 integer (c_int) :: status
923 logical (c_bool) :: match_case_
924
925 if ( present( match_case ) ) then
926 match_case_ = match_case
927 else
928 match_case_ = .false._c_bool
929 endif
930
931 count = 0
932
933 if ( match_case_ ) then
934
935 do i=1, this%count
936
937 if ( this%get(i) .strequal. substr ) count = count + 1
938
939 enddo
940
941 else
942
943 do i=1, this%count
944
945 if ( this%get(i) .strapprox. substr ) count = count + 1
946
947 enddo
948
949 endif
950
952
953!--------------------------------------------------------------------------------------------------
954
955 function return_subset_of_partial_matches_fn( this, substr ) result(new_fstring)
956
957 class(fstring_list_t), intent(inout) :: this
958 character (len=*), intent(in) :: substr
959 type (fstring_list_t) :: new_fstring
960
961 ! [ LOCALS ]
962 integer (c_int) :: i
963 character (len=:), allocatable :: temp_str
964
965 do i=1, this%count
966 temp_str = this%get(i)
967 if ( temp_str .containssimilar. substr ) call new_fstring%append(temp_str)
968 enddo
969
970 if ( new_fstring%count == 0 ) new_fstring = "<NA>"
971
973
974!--------------------------------------------------------------------------------------------------
975
976 function return_indices_of_matching_list_entries_fn(this, character_str) result(index_values)
977
978 class(fstring_list_t), intent(inout) :: this
979 character (len=*), intent(in) :: character_str
980 integer (c_int), allocatable :: index_values(:)
981
982 ! [ LOCALS ]
983 integer (c_int) :: i
984 integer (c_int) :: match_index
985 logical (c_bool) :: string_present( this%count )
986 integer (c_int) :: number_of_matches
987
988 string_present = .false._c_bool
989 match_index = 0
990
991 do i=1, this%count
992 if ( this%get(i) .strapprox. character_str ) string_present(i) = .true._c_bool
993 enddo
994
995 number_of_matches = count(string_present)
996 if (number_of_matches > 0 ) then
997 allocate( index_values(number_of_matches) )
998 do i=1, this%count
999 if (string_present(i)) then
1000 match_index = match_index + 1
1001 index_values(match_index) = i
1002 endif
1003 enddo
1004 else
1005 allocate( index_values(1) )
1006 index_values(1) = -9999
1007 endif
1008
1010
1011!--------------------------------------------------------------------------------------------------
1012
1013 function return_list_of_unique_values_fn(this) result(new_fstring)
1014
1015 class(fstring_list_t), intent(inout) :: this
1016 type (fstring_list_t) :: new_fstring
1017
1018 integer (c_int) :: i
1019 character (len=:), allocatable :: temp_str
1020
1021 do i=1, this%count
1022
1023 temp_str = this%get(i)
1024 if ( new_fstring%count_matching( temp_str ) == 0 ) call new_fstring%append(temp_str)
1025
1026 enddo
1027
1028 if ( new_fstring%count == 0 ) new_fstring = "<NA>"
1029
1031
1032!--------------------------------------------------------------------------------------------------
1033
1034 subroutine print_as_markdown_sub(this, lu)
1035
1036 use iso_fortran_env, only : output_unit
1037
1038 class(fstring_list_t), intent(inout) :: this
1039 integer (c_int), optional :: lu
1040
1041 ! [ LOCALS ]
1042 integer (c_int) :: lu_
1043 integer (c_int) :: i
1044
1045 if (present(lu) ) then
1046 lu_ = lu
1047 else
1048 lu_ = output_unit
1049 endif
1050
1051 write(lu_, fmt="('|',a,t21,'|',a,t72,'|')") "Index","Value"
1052 write(lu_, fmt="('|',a,t21,'|',a,t72,'|')") repeat("-",18)//":", repeat("-",49)//":"
1053
1054 do i=1, this%count
1055
1056 write(lu_, fmt="('|',i10,t21,'|',a,t72,'|')") i, this%get(i)
1057
1058 enddo
1059
1060 end subroutine print_as_markdown_sub
1061
1062end module fstring_list
logical(c_bool) function, dimension(:), allocatable retrieve_values_as_logical_fn(this)
subroutine append_character_array_to_fstring_sub(this, character_str)
real(c_float) function, dimension(:), allocatable retrieve_values_as_float_fn(this)
subroutine list_finalize_sub(this)
subroutine quicksort_int_sub(this, sort_order)
character(len=:) function, allocatable retrieve_values_for_range_of_indices_fn(this, start_indx, end_indx)
subroutine append_character_to_fstring_sub(this, character_str)
subroutine append_fstring_to_fstring_sub(this, other_fstring)
type(fstring_list_t) function return_subset_of_partial_matches_fn(this, substr)
character(len=:) function, allocatable retrieve_value_from_list_at_index_fn(this, index_val)
logical(c_bool) function are_there_missing_list_values_fn(this)
integer(c_int) function, dimension(:), allocatable return_indices_of_matching_list_entries_fn(this, character_str)
subroutine assign_fstring_to_character_sub(character_str, string_list)
subroutine print_as_markdown_sub(this, lu)
integer(c_int) function, dimension(:), allocatable retrieve_values_as_integer_fn(this)
integer(c_int) function return_count_of_matching_strings_fn(this, substr, match_case)
subroutine quicksort_float_sub(this, sort_order)
subroutine assign_character_to_fstring_sub(this, character_str)
character(len=:) function, allocatable list_all_fn(this, delimiter_chr)
subroutine clear_list_sub(this)
real(c_double) function, dimension(:), allocatable retrieve_values_as_double_fn(this)
recursive subroutine qsort_alpha(sort_group, nrec)
recursive subroutine qsort_float(sort_group, nrec)
integer(c_int) function count_strings_in_list_fn(this)
subroutine replace_value_at_index_sub(this, index_val, character_str)
subroutine print_all_entries_sub(this)
subroutine quicksort_alpha_sub(this, sort_order)
type(fstring_list_t) function split_character_into_fstring_list_fn(character_str, delimiter_chr)
type(fstring_list_t) function return_list_of_unique_values_fn(this)
recursive subroutine qsort_int(sort_group, nrec)
integer(c_int), parameter, private na_int
Definition fstring.F90:181
real(c_double), parameter, private na_double
Definition fstring.F90:183
real(c_float), parameter, private na_float
Definition fstring.F90:182