|
6 | 6 | module stdlib_strings |
7 | 7 | use stdlib_ascii, only : whitespace |
8 | 8 | use stdlib_string_type, only : string_type, char, verify |
| 9 | + use stdlib_math, only: clip |
9 | 10 | implicit none |
10 | 11 | private |
11 | 12 |
|
12 | 13 | public :: strip, chomp |
13 | 14 | public :: starts_with, ends_with |
| 15 | + public :: slice |
14 | 16 |
|
15 | 17 |
|
16 | 18 | !> Remove leading and trailing whitespace characters. |
@@ -56,7 +58,13 @@ module stdlib_strings |
56 | 58 | module procedure :: ends_with_string_char |
57 | 59 | module procedure :: ends_with_char_string |
58 | 60 | module procedure :: ends_with_char_char |
59 | | - end interface ends_with |
| 61 | + end interface |
| 62 | + |
| 63 | + !> |
| 64 | + interface slice |
| 65 | + module procedure :: slice_string |
| 66 | + module procedure :: slice_char |
| 67 | + end interface slice |
60 | 68 |
|
61 | 69 |
|
62 | 70 | contains |
@@ -290,5 +298,72 @@ elemental function ends_with_string_string(string, substring) result(match) |
290 | 298 |
|
291 | 299 | end function ends_with_string_string |
292 | 300 |
|
| 301 | + !> Slices the region between first and last indexes of the input |
| 302 | + !> string by taking strides of length stride |
| 303 | + elemental function slice_string(string, first, last, stride, include_last) result(sliced_string) |
| 304 | + type(string_type), intent(in) :: string |
| 305 | + integer, intent(in), optional :: first, last, stride |
| 306 | + logical, intent(in), optional :: include_last |
| 307 | + type(string_type) :: sliced_string |
| 308 | + |
| 309 | + sliced_string = string_type(slice(char(string), first, last, stride, include_last)) |
| 310 | + |
| 311 | + end function slice_string |
| 312 | + |
| 313 | + !> Slices the region between first and last indexes of the input |
| 314 | + !> character sequence by taking strides of length stride |
| 315 | + pure function slice_char(string, first, last, stride, include_last) result(sliced_string) |
| 316 | + character(len=*), intent(in) :: string |
| 317 | + integer, intent(in), optional :: first, last, stride |
| 318 | + logical, intent(in), optional :: include_last |
| 319 | + integer :: first_index, last_index, stride_vector, n, i, j |
| 320 | + character(len=:), allocatable :: sliced_string |
| 321 | + |
| 322 | + first_index = 1 |
| 323 | + last_index = len(string) |
| 324 | + stride_vector = 1 |
| 325 | + if (len(string) > 0) then |
| 326 | + if (present(stride)) then |
| 327 | + if (stride /= 0) then |
| 328 | + if (stride < 0) then |
| 329 | + first_index = len(string) |
| 330 | + last_index = 1 |
| 331 | + end if |
| 332 | + stride_vector = stride |
| 333 | + end if |
| 334 | + else |
| 335 | + if (present(first) .and. present(last)) then |
| 336 | + if (last < first) then |
| 337 | + stride_vector = -1 |
| 338 | + end if |
| 339 | + end if |
| 340 | + end if |
| 341 | + |
| 342 | + if (present(first)) then |
| 343 | + first_index = clip(first, 1, len(string)) |
| 344 | + end if |
| 345 | + if (present(last)) then |
| 346 | + last_index = clip(last, 1, len(string)) |
| 347 | + end if |
| 348 | + |
| 349 | + n = int((last_index - first_index) / stride_vector) |
| 350 | + allocate(character(len=max(0, n + 1)) :: sliced_string) |
| 351 | + |
| 352 | + if (present(include_last)) then |
| 353 | + if (include_last) then |
| 354 | + first_index = last_index - (n * stride_vector) |
| 355 | + end if |
| 356 | + end if |
| 357 | + |
| 358 | + j = 1 |
| 359 | + do i = first_index, last_index, stride_vector |
| 360 | + sliced_string(j:j) = string(i:i) |
| 361 | + j = j + 1 |
| 362 | + end do |
| 363 | + else |
| 364 | + sliced_string = '' |
| 365 | + end if |
| 366 | + end function slice_char |
| 367 | + |
293 | 368 |
|
294 | 369 | end module stdlib_strings |
0 commit comments