Skip to content

Commit 8ef2f81

Browse files
authored
Merge pull request #32 from ivan-pi/ascii
Add module for validating ASCII characters and upper/lower conversion
2 parents c6b8119 + c1a51e2 commit 8ef2f81

File tree

5 files changed

+750
-0
lines changed

5 files changed

+750
-0
lines changed

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
set(SRC
2+
stdlib_experimental_ascii.f90
23
stdlib_experimental_io.f90
34
stdlib_experimental_error.f90
45
)

src/stdlib_experimental_ascii.f90

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
module stdlib_experimental_ascii
2+
3+
implicit none
4+
private
5+
6+
! Character validation functions
7+
public :: is_alpha, is_alphanum
8+
public :: is_digit, is_hex_digit, is_octal_digit
9+
public :: is_control, is_white, is_blank
10+
public :: is_ascii, is_punctuation
11+
public :: is_graphical, is_printable
12+
public :: is_lower, is_upper
13+
14+
! Character conversion functions
15+
public :: to_lower, to_upper
16+
17+
! All control characters in the ASCII table (see www.asciitable.com).
18+
character(len=1), public, parameter :: NUL = achar(z'00') !! Null
19+
character(len=1), public, parameter :: SOH = achar(z'01') !! Start of heading
20+
character(len=1), public, parameter :: STX = achar(z'02') !! Start of text
21+
character(len=1), public, parameter :: ETX = achar(z'03') !! End of text
22+
character(len=1), public, parameter :: EOT = achar(z'04') !! End of transmission
23+
character(len=1), public, parameter :: ENQ = achar(z'05') !! Enquiry
24+
character(len=1), public, parameter :: ACK = achar(z'06') !! Acknowledge
25+
character(len=1), public, parameter :: BEL = achar(z'07') !! Bell
26+
character(len=1), public, parameter :: BS = achar(z'08') !! Backspace
27+
character(len=1), public, parameter :: TAB = achar(z'09') !! Horizontal tab
28+
character(len=1), public, parameter :: LF = achar(z'0A') !! NL line feed, new line
29+
character(len=1), public, parameter :: VT = achar(z'0B') !! Vertical tab
30+
character(len=1), public, parameter :: FF = achar(z'0C') !! NP form feed, new page
31+
character(len=1), public, parameter :: CR = achar(z'0D') !! Carriage return
32+
character(len=1), public, parameter :: SO = achar(z'0E') !! Shift out
33+
character(len=1), public, parameter :: SI = achar(z'0F') !! Shift in
34+
character(len=1), public, parameter :: DLE = achar(z'10') !! Data link escape
35+
character(len=1), public, parameter :: DC1 = achar(z'11') !! Device control 1
36+
character(len=1), public, parameter :: DC2 = achar(z'12') !! Device control 2
37+
character(len=1), public, parameter :: DC3 = achar(z'13') !! Device control 3
38+
character(len=1), public, parameter :: DC4 = achar(z'14') !! Device control 4
39+
character(len=1), public, parameter :: NAK = achar(z'15') !! Negative acknowledge
40+
character(len=1), public, parameter :: SYN = achar(z'16') !! Synchronous idle
41+
character(len=1), public, parameter :: ETB = achar(z'17') !! End of transmission block
42+
character(len=1), public, parameter :: CAN = achar(z'18') !! Cancel
43+
character(len=1), public, parameter :: EM = achar(z'19') !! End of medium
44+
character(len=1), public, parameter :: SUB = achar(z'1A') !! Substitute
45+
character(len=1), public, parameter :: ESC = achar(z'1B') !! Escape
46+
character(len=1), public, parameter :: FS = achar(z'1C') !! File separator
47+
character(len=1), public, parameter :: GS = achar(z'1D') !! Group separator
48+
character(len=1), public, parameter :: RS = achar(z'1E') !! Record separator
49+
character(len=1), public, parameter :: US = achar(z'1F') !! Unit separator
50+
character(len=1), public, parameter :: DEL = achar(z'7F') !! Delete
51+
52+
! Constant character sequences
53+
character(len=*), public, parameter :: fullhex_digits = "0123456789ABCDEFabcdef" !! 0 .. 9A .. Fa .. f
54+
character(len=*), public, parameter :: hex_digits = fullhex_digits(1:16) !! 0 .. 9A .. F
55+
character(len=*), public, parameter :: lowerhex_digits = "0123456789abcdef" !! 0 .. 9a .. f
56+
character(len=*), public, parameter :: digits = hex_digits(1:10) !! 0 .. 9
57+
character(len=*), public, parameter :: octal_digits = digits(1:8) !! 0 .. 7
58+
character(len=*), public, parameter :: letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" !! A .. Za .. z
59+
character(len=*), public, parameter :: uppercase = letters(1:26) !! A .. Z
60+
character(len=*), public, parameter :: lowercase = letters(27:) !! a .. z
61+
character(len=*), public, parameter :: whitespace = " "//TAB//VT//CR//LF//FF !! ASCII _whitespace
62+
63+
contains
64+
65+
!> Checks whether `c` is an ASCII letter (A .. Z, a .. z).
66+
pure logical function is_alpha(c)
67+
character(len=1), intent(in) :: c !! The character to test.
68+
is_alpha = (c >= 'A' .and. c <= 'Z') .or. (c >= 'a' .and. c <= 'z')
69+
end function
70+
71+
!> Checks whether `c` is a letter or a number (0 .. 9, a .. z, A .. Z).
72+
pure logical function is_alphanum(c)
73+
character(len=1), intent(in) :: c !! The character to test.
74+
is_alphanum = (c >= '0' .and. c <= '9') .or. (c >= 'a' .and. c <= 'z') &
75+
.or. (c >= 'A' .and. c <= 'Z')
76+
end function
77+
78+
!> Checks whether or not `c` is in the ASCII character set -
79+
! i.e. in the range 0 .. 0x7F.
80+
pure logical function is_ascii(c)
81+
character(len=1), intent(in) :: c !! The character to test.
82+
is_ascii = iachar(c) <= z'7F'
83+
end function
84+
85+
!> Checks whether `c` is a control character.
86+
pure logical function is_control(c)
87+
character(len=1), intent(in) :: c !! The character to test.
88+
integer :: ic
89+
ic = iachar(c)
90+
is_control = ic < z'20' .or. ic == z'7F'
91+
end function
92+
93+
!> Checks whether `c` is a digit (0 .. 9).
94+
pure logical function is_digit(c)
95+
character(len=1), intent(in) :: c !! The character to test.
96+
is_digit = ('0' <= c) .and. (c <= '9')
97+
end function
98+
99+
!> Checks whether `c` is a digit in base 8 (0 .. 7).
100+
pure logical function is_octal_digit(c)
101+
character(len=1), intent(in) :: c !! The character to test.
102+
is_octal_digit = (c >= '0') .and. (c <= '7');
103+
end function
104+
105+
!> Checks whether `c` is a digit in base 16 (0 .. 9, A .. F, a .. f).
106+
pure logical function is_hex_digit(c)
107+
character(len=1), intent(in) :: c !! The character to test.
108+
is_hex_digit = (c >= '0' .and. c <= '9') .or. (c >= 'a' .and. c <= 'f') &
109+
.or. (c >= 'A' .and. c <= 'F')
110+
end function
111+
112+
!> Checks whether or not `c` is a punctuation character. That includes
113+
! all ASCII characters which are not control characters, letters,
114+
! digits, or whitespace.
115+
pure logical function is_punctuation(c)
116+
character(len=1), intent(in) :: c !! The character to test.
117+
integer :: ic
118+
ic = iachar(c) ! '~' '!'
119+
is_punctuation = (ic <= z'7E') .and. (ic >= z'21') .and. &
120+
(.not. is_alphanum(c))
121+
end function
122+
123+
!> Checks whether or not `c` is a printable character other than the
124+
! space character.
125+
pure logical function is_graphical(c)
126+
character(len=1), intent(in) :: c !! The character to test.
127+
integer :: ic
128+
ic = iachar(c) ! '!' '~'
129+
is_graphical = (z'21' <= ic) .and. (ic <= z'7E')
130+
end function
131+
132+
!> Checks whether or not `c` is a printable character - including the
133+
! space character.
134+
pure logical function is_printable(c)
135+
character(len=1), intent(in) :: c !! The character to test.
136+
integer :: ic
137+
ic = iachar(c) ! '~'
138+
is_printable = c >= ' ' .and. ic <= z'7E'
139+
end function
140+
141+
!> Checks whether `c` is a lowercase ASCII letter (a .. z).
142+
pure logical function is_lower(c)
143+
character(len=1), intent(in) :: c !! The character to test.
144+
is_lower = (c >= 'a') .and. (c <= 'z')
145+
end function
146+
147+
!> Checks whether `c` is an uppercase ASCII letter (A .. Z).
148+
pure logical function is_upper(c)
149+
character(len=1), intent(in) :: c !! The character to test.
150+
is_upper = (c >= 'A') .and. (c <= 'Z')
151+
end function
152+
153+
!> Checks whether or not `c` is a whitespace character. That includes the
154+
! space, tab, vertical tab, form feed, carriage return, and linefeed
155+
! characters.
156+
pure logical function is_white(c)
157+
character(len=1), intent(in) :: c !! The character to test.
158+
integer :: ic
159+
ic = iachar(c) ! TAB, LF, VT, FF, CR
160+
is_white = (c == ' ') .or. (ic >= z'09' .and. ic <= z'0D');
161+
end function
162+
163+
!> Checks whether or not `c` is a blank character. That includes the
164+
! only the space and tab characters
165+
pure logical function is_blank(c)
166+
character(len=1), intent(in) :: c !! The character to test.
167+
integer :: ic
168+
ic = iachar(c) ! TAB
169+
is_blank = (c == ' ') .or. (ic == z'09');
170+
end function
171+
172+
!> Returns the corresponding lowercase letter, if `c` is an uppercase
173+
! ASCII character, otherwise `c` itself.
174+
pure function to_lower(c) result(t)
175+
character(len=1), intent(in) :: c !! A character.
176+
character(len=1) :: t
177+
integer :: diff
178+
diff = iachar('A')-iachar('a')
179+
t = c
180+
! if uppercase, make lowercase
181+
if (is_upper(t)) t = achar(iachar(t) - diff)
182+
end function
183+
184+
!> Returns the corresponding uppercase letter, if `c` is a lowercase
185+
! ASCII character, otherwise `c` itself.
186+
pure function to_upper(c) result(t)
187+
character(len=1), intent(in) :: c !! A character.
188+
character(len=1) :: t
189+
integer :: diff
190+
diff = iachar('A')-iachar('a')
191+
t = c
192+
! if lowercase, make uppercase
193+
if (is_lower(t)) t = achar(iachar(t) + diff)
194+
end function
195+
196+
end module

src/tests/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
add_subdirectory(ascii)
12
add_subdirectory(loadtxt)
3+

src/tests/ascii/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include_directories(${PROJECT_BINARY_DIR}/src)
2+
3+
project(ascii)
4+
5+
add_executable(test_ascii test_ascii.f90)
6+
target_link_libraries(test_ascii fortran_stdlib)
7+
8+
add_test(test_ascii ${PROJECT_BINARY_DIR}/test_ascii)
9+

0 commit comments

Comments
 (0)