Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented intelligent slice functionality #414

Merged
merged 19 commits into from
Jun 12, 2021
Merged
Changes from 9 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
90eb9aa
implemented slice function for stdlib_ascii
aman-godara May 23, 2021
e235bc4
added module dependencies of stdlib_math for function slice in Makefi…
aman-godara May 23, 2021
0742ca0
changed names from start to first and end to last
aman-godara May 24, 2021
1a5f78c
forgot to change the dummy argument start to first
aman-godara May 24, 2021
15827d2
shifted slice from stdlib_ascii to stdlib_strings and modified module…
aman-godara May 24, 2021
c7c1e48
removed include_last functionality
aman-godara May 25, 2021
ac607f1
added tests for slice function (with no include_last functionality)
aman-godara May 25, 2021
9d72c69
made complete use of slice interface: added test cases for character …
aman-godara May 25, 2021
a733bc3
documented function slice, corrected documentation of to_title and to…
aman-godara May 26, 2021
fa88905
improved function slice for invalid cases, added new invalid test cases
aman-godara May 27, 2021
42a905d
improved the implementation of last commit fa88905
aman-godara May 28, 2021
ffcb7e4
removed redundant outer loop, improved documentation of slice function
aman-godara May 29, 2021
4598eec
removed dependency of clip function by stdlib_strings.f90
aman-godara May 29, 2021
24d417f
improved documentation and comments for function slice
aman-godara Jun 7, 2021
323bcd9
Add general tester against intrinsic array slice
awvwgk Jun 10, 2021
a895085
Merge pull request #3 from awvwgk/slice
aman-godara Jun 10, 2021
d60dad3
added -inf and +inf concept to make code more intuitive, added descri…
aman-godara Jun 11, 2021
048b638
added the concept of +inf and -inf in documentation
aman-godara Jun 11, 2021
d38e0f4
added fail messages to unit tests
aman-godara Jun 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/specs/stdlib_string_type.md
Original file line number Diff line number Diff line change
@@ -1254,7 +1254,7 @@ The result is a scalar `string_type` value.

```fortran
program demo_to_title
use stdlib_string_type, only: string_type, to_title
use stdlib_string_type
implicit none
type(string_type) :: string, titlecase_string

@@ -1302,7 +1302,7 @@ The result is a scalar `string_type` value.

```fortran
program demo_to_sentence
use stdlib_string_type, only: string_type, to_sentence
use stdlib_string_type
implicit none
type(string_type) :: string, sentencecase_string

61 changes: 61 additions & 0 deletions doc/specs/stdlib_strings.md
Original file line number Diff line number Diff line change
@@ -192,3 +192,64 @@ program demo
print'(a)', ends_with("pattern", "pat") ! F
end program demo
```


<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
### `slice`

#### Description

Extracts the characters from the defined region of the input string.
Argument `first` and `last` defines the region for the function `slice` to operate.
Extraction starts from the index `first` and takes stride of length `stride`.
Argument `stride` cannot take the value 0.

#### Syntax

`string = [[stdlib_strings(module):slice(interface)]] (string, first, last, stride)`

#### Status

Experimental

#### Class

Pure function.

#### Argument

- `string`: Character scalar or [[stdlib_string_type(module):string_type(type)]]
This argument is intent(in).
- `first`: integer
This argument is intent(in) and optional.
- `last`: integer
This argument is intent(in) and optional.
- `stride`: integer
This argument is intent(in) and optional.

#### Result value

The result is of the same type as `string`.

#### Example

```fortran
program demo_slice
use stdlib_string_type
use stdlib_strings, only : slice
implicit none
type(string_type) :: string
character(len=10) :: char

string = "abcdefghij"
! string <-- "abcdefghij"

char = "abcdefghij"
! char <-- "abcdefghij"

print'(a)', slice("abcdefghij", 2, 6, 2) ! "bdf"
print'(a)', slice(string, 2, 6, 2) ! "bdf"
print'(a)', slice(char, 2, 6, 2) ! "bdf"

end program demo_slice
```
7 changes: 5 additions & 2 deletions src/Makefile.manual
Original file line number Diff line number Diff line change
@@ -112,6 +112,9 @@ stdlib_stats_var.o: \
stdlib_stats_distribution_PRNG.o: \
stdlib_kinds.o \
stdlib_error.o
stdlib_string_type.o: stdlib_ascii.o stdlib_kinds.o
stdlib_strings.o: stdlib_ascii.o stdlib_string_type.o
stdlib_string_type.o: stdlib_ascii.o \
stdlib_kinds.o
stdlib_strings.o: stdlib_ascii.o \
stdlib_string_type.o \
stdlib_math.o
stdlib_math.o: stdlib_kinds.o
72 changes: 72 additions & 0 deletions src/stdlib_strings.f90
Original file line number Diff line number Diff line change
@@ -6,11 +6,13 @@
module stdlib_strings
use stdlib_ascii, only : whitespace
use stdlib_string_type, only : string_type, char, verify
use stdlib_math, only: clip
implicit none
private

public :: strip, chomp
public :: starts_with, ends_with
public :: slice


!> Remove leading and trailing whitespace characters.
@@ -57,6 +59,14 @@ module stdlib_strings
module procedure :: ends_with_char_string
module procedure :: ends_with_char_char
end interface ends_with

!> Slices the input string to return a new string
!>
!> Version: experimental
interface slice
module procedure :: slice_string
module procedure :: slice_char
end interface slice


contains
@@ -290,5 +300,67 @@ elemental function ends_with_string_string(string, substring) result(match)

end function ends_with_string_string

!> Slices the region between the input 'first' and 'last' index (both inclusive)
!> of the input 'string' by taking strides of length 'stride'
!> Returns a new string_type object
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

!> Slices the region between the input '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, n, i, j
character(len=:), allocatable :: sliced_string

if (len(string) > 0) then
first_index = 1
last_index = len(string)
stride_vector = 1

if (present(stride)) then
if (stride /= 0) then
if (stride < 0) then
first_index = len(string)
last_index = 1
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 = clip(first, 1, len(string))
end if
if (present(last)) then
last_index = clip(last, 1, len(string))
end if

n = int((last_index - first_index) / stride_vector)
allocate(character(len=max(0, n + 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
else
sliced_string = ""
end if
end function slice_char


end module stdlib_strings
42 changes: 42 additions & 0 deletions src/tests/string/test_string_functions.f90
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ module test_string_functions
use stdlib_error, only : check
use stdlib_string_type, only : string_type, assignment(=), operator(==), &
to_lower, to_upper, to_title, to_sentence, reverse
use stdlib_strings, only: slice
implicit none

contains
@@ -52,6 +53,46 @@ subroutine test_reverse_string

end subroutine test_reverse_string

subroutine test_slice_string
type(string_type) :: test_string
character(len=:), allocatable :: test_char
test_string = "abcdefghijklmnopqrstuvwxyz"
test_char = "abcdefghijklmnopqrstuvwxyz"

call check(slice(test_string, 2, 16, 3) == "behkn", &
'function slice failed', warn=.true.)
call check(slice(test_char, 15, stride=-1) == "onmlkjihgfedcba", &
'function slice failed', warn=.true.)
call check(slice(test_string, last=22, stride=-1) == "zyxwv", &
'function slice failed', warn=.true.)
call check(slice(test_char, 7, 2) == "gfedcb", &
'function slice failed', warn=.true.)
call check(slice(test_string, 7, 2, 1) == "", &
'function slice failed', warn=.true.)
call check(slice(test_char, 2, 6, -1) == "", &
'function slice failed', warn=.true.)
call check(slice(test_string, stride=-1) == "zyxwvutsrqponmlkjihgfedcba", &
'function slice failed', warn=.true.)
call check(slice(test_string, 7, 7, -4) == "g", &
'function slice failed', warn=.true.)
call check(slice(test_char, 7, 7, 3) == "g", &
'function slice failed', warn=.true.)
call check(slice(test_string, 7, 7, 3) == "g", &
'function slice failed', warn=.true.)
call check(slice(test_char, 7, -10) == "gfedcba", &
'function slice failed', warn=.true.)
call check(slice(test_string, 500, 22) == "zyxwv", &
'function slice failed', warn=.true.)

test_string = ""
test_char = ""
call check(slice(test_string, 2, 16, 3) == "", &
'function slice failed', warn=.true.)
call check(slice(test_char, 2, 16, 3) == "", &
'function slice failed', warn=.true.)

end subroutine test_slice_string

end module test_string_functions


@@ -64,5 +105,6 @@ program tester
call test_to_title_string
call test_to_sentence_string
call test_reverse_string
call test_slice_string

end program tester