| ... | @@ -1,16 +1,18 @@ | ... | @@ -1,16 +1,18 @@ |
| 1 | // Does NOT look at the locale the way C89's toupper(3), isspace() et cetera does. | 1 | //! The 7-bit [ASCII](https://en.wikipedia.org/wiki/ASCII) character encoding standard. |
| 2 | // I could have taken only a u7 to make this clear, but it would be slower | 2 | //! |
| 3 | // It is my opinion that encodings other than UTF-8 should not be supported. | 3 | //! This is not to be confused with the 8-bit [extended ASCII](https://en.wikipedia.org/wiki/Extended_ASCII) character encoding. |
| 4 | // | 4 | //! |
| 5 | // (and 128 bytes is not much to pay). | 5 | //! Even though this module concerns itself with 7-bit ASCII, |
| 6 | // Also does not handle Unicode character classes. | 6 | //! functions use `u8` as the type instead of `u7` for convenience and compatibility. |
| 7 | // | 7 | //! Characters outside of the 7-bit range are gracefully handled (e.g. by returning `false`). |
| 8 | // https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/USASCII_code_chart.png/1200px-USASCII_code_chart.png | 8 | //! |
| | 9 | //! See also: https://en.wikipedia.org/wiki/ASCII#Character_set |
| 9 | | 10 | |
| 10 | const std = @import("std"); | 11 | const std = @import("std"); |
| 11 | | 12 | |
| 12 | /// Contains constants for the C0 control codes of the ASCII encoding. | 13 | /// The C0 control codes of the ASCII encoding. |
| 13 | /// https://en.wikipedia.org/wiki/C0_and_C1_control_codes | 14 | /// |
| | 15 | /// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `is_control`. |
| 14 | pub const control_code = struct { | 16 | pub const control_code = struct { |
| 15 | /// Null. | 17 | /// Null. |
| 16 | pub const nul = 0x00; | 18 | pub const nul = 0x00; |
| ... | @@ -237,15 +239,20 @@ pub const spaces = whitespace; | ... | @@ -237,15 +239,20 @@ pub const spaces = whitespace; |
| 237 | /// DEPRECATED: use `isHex`. | 239 | /// DEPRECATED: use `isHex`. |
| 238 | pub const isXDigit = isHex; | 240 | pub const isXDigit = isHex; |
| 239 | | 241 | |
| | 242 | /// Returns whether the character is alphanumeric. This is case-insensitive. |
| 240 | pub fn isAlphanumeric(c: u8) bool { | 243 | pub fn isAlphanumeric(c: u8) bool { |
| 241 | return (combinedTable[c] & ((@as(u8, 1) << @enumToInt(tIndex.Alpha)) | | 244 | return (combinedTable[c] & ((@as(u8, 1) << @enumToInt(tIndex.Alpha)) | |
| 242 | @as(u8, 1) << @enumToInt(tIndex.Digit))) != 0; | 245 | @as(u8, 1) << @enumToInt(tIndex.Digit))) != 0; |
| 243 | } | 246 | } |
| 244 | | 247 | |
| | 248 | /// Returns whether the character is alphabetic. This is case-insensitive. |
| 245 | pub fn isAlphabetic(c: u8) bool { | 249 | pub fn isAlphabetic(c: u8) bool { |
| 246 | return inTable(c, tIndex.Alpha); | 250 | return inTable(c, tIndex.Alpha); |
| 247 | } | 251 | } |
| 248 | | 252 | |
| | 253 | /// Returns whether the character is a control character. |
| | 254 | /// |
| | 255 | /// See also: `control_code`. |
| 249 | pub fn isControl(c: u8) bool { | 256 | pub fn isControl(c: u8) bool { |
| 250 | return c <= control_code.us or c == control_code.del; | 257 | return c <= control_code.us or c == control_code.del; |
| 251 | } | 258 | } |
| ... | @@ -259,10 +266,13 @@ pub fn isGraph(c: u8) bool { | ... | @@ -259,10 +266,13 @@ pub fn isGraph(c: u8) bool { |
| 259 | return inTable(c, tIndex.Graph); | 266 | return inTable(c, tIndex.Graph); |
| 260 | } | 267 | } |
| 261 | | 268 | |
| | 269 | /// Returns whether the character is lowercased. |
| 262 | pub fn isLower(c: u8) bool { | 270 | pub fn isLower(c: u8) bool { |
| 263 | return inTable(c, tIndex.Lower); | 271 | return inTable(c, tIndex.Lower); |
| 264 | } | 272 | } |
| 265 | | 273 | |
| | 274 | /// Returns whether the character has some graphical representation and can be printed. |
| | 275 | /// This also returns `true` for the space character. |
| 266 | pub fn isPrint(c: u8) bool { | 276 | pub fn isPrint(c: u8) bool { |
| 267 | return inTable(c, tIndex.Graph) or c == ' '; | 277 | return inTable(c, tIndex.Graph) or c == ' '; |
| 268 | } | 278 | } |
| ... | @@ -271,6 +281,7 @@ pub fn isPunct(c: u8) bool { | ... | @@ -271,6 +281,7 @@ pub fn isPunct(c: u8) bool { |
| 271 | return inTable(c, tIndex.Punct); | 281 | return inTable(c, tIndex.Punct); |
| 272 | } | 282 | } |
| 273 | | 283 | |
| | 284 | /// Returns whether this character is included in `whitespace`. |
| 274 | pub fn isWhitespace(c: u8) bool { | 285 | pub fn isWhitespace(c: u8) bool { |
| 275 | return inTable(c, tIndex.Space); | 286 | return inTable(c, tIndex.Space); |
| 276 | } | 287 | } |
| ... | @@ -289,10 +300,12 @@ test "whitespace" { | ... | @@ -289,10 +300,12 @@ test "whitespace" { |
| 289 | } | 300 | } |
| 290 | } | 301 | } |
| 291 | | 302 | |
| | 303 | /// Returns whether the character is uppercased. |
| 292 | pub fn isUpper(c: u8) bool { | 304 | pub fn isUpper(c: u8) bool { |
| 293 | return inTable(c, tIndex.Upper); | 305 | return inTable(c, tIndex.Upper); |
| 294 | } | 306 | } |
| 295 | | 307 | |
| | 308 | /// Returns whether the character is a hexadecimal digit. This is case-insensitive. |
| 296 | pub fn isHex(c: u8) bool { | 309 | pub fn isHex(c: u8) bool { |
| 297 | return inTable(c, tIndex.Hex); | 310 | return inTable(c, tIndex.Hex); |
| 298 | } | 311 | } |
| ... | @@ -306,6 +319,7 @@ pub fn isBlank(c: u8) bool { | ... | @@ -306,6 +319,7 @@ pub fn isBlank(c: u8) bool { |
| 306 | return (c == ' ') or (c == '\x09'); | 319 | return (c == ' ') or (c == '\x09'); |
| 307 | } | 320 | } |
| 308 | | 321 | |
| | 322 | /// Upper-cases the character and returns it as-is if it's already upper-cased. |
| 309 | pub fn toUpper(c: u8) u8 { | 323 | pub fn toUpper(c: u8) u8 { |
| 310 | if (isLower(c)) { | 324 | if (isLower(c)) { |
| 311 | return c & 0b11011111; | 325 | return c & 0b11011111; |
| ... | @@ -314,6 +328,7 @@ pub fn toUpper(c: u8) u8 { | ... | @@ -314,6 +328,7 @@ pub fn toUpper(c: u8) u8 { |
| 314 | } | 328 | } |
| 315 | } | 329 | } |
| 316 | | 330 | |
| | 331 | /// Lower-cases the character and returns it as-is if it's already lower-cased. |
| 317 | pub fn toLower(c: u8) u8 { | 332 | pub fn toLower(c: u8) u8 { |
| 318 | if (isUpper(c)) { | 333 | if (isUpper(c)) { |
| 319 | return c | 0b00100000; | 334 | return c | 0b00100000; |
| ... | @@ -392,7 +407,7 @@ test "allocUpperString" { | ... | @@ -392,7 +407,7 @@ test "allocUpperString" { |
| 392 | try std.testing.expectEqualStrings("ABCDEFGHIJKLMNOPQRST0234+💩!", result); | 407 | try std.testing.expectEqualStrings("ABCDEFGHIJKLMNOPQRST0234+💩!", result); |
| 393 | } | 408 | } |
| 394 | | 409 | |
| 395 | /// Compares strings `a` and `b` case insensitively and returns whether they are equal. | 410 | /// Compares strings `a` and `b` case-insensitively and returns whether they are equal. |
| 396 | pub fn eqlIgnoreCase(a: []const u8, b: []const u8) bool { | 411 | pub fn eqlIgnoreCase(a: []const u8, b: []const u8) bool { |
| 397 | if (a.len != b.len) return false; | 412 | if (a.len != b.len) return false; |
| 398 | for (a) |a_c, i| { | 413 | for (a) |a_c, i| { |