mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-13 06:43:52 +00:00
@@ -16,93 +16,103 @@ import std/private/strimpl
|
||||
|
||||
|
||||
when defined(js):
|
||||
func startsWith*(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".}
|
||||
func jsStartsWith(s, prefix: cstring): bool {.importjs: "#.startsWith(#)".}
|
||||
func jsEndsWith(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".}
|
||||
|
||||
func endsWith*(s, suffix: cstring): bool {.importjs: "#.endsWith(#)".}
|
||||
|
||||
func cmpIgnoreStyle*(a, b: cstring): int =
|
||||
func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} =
|
||||
## Returns true if `s` starts with `prefix`.
|
||||
##
|
||||
## JS backend uses native `String.prototype.startsWith`.
|
||||
runnableExamples:
|
||||
assert startsWith(cstring"Hello, Nimion", cstring"Hello")
|
||||
assert not startsWith(cstring"Hello, Nimion", cstring"Nimion")
|
||||
assert startsWith(cstring"Hello", cstring"")
|
||||
when nimvm:
|
||||
startsWithImpl(s, prefix)
|
||||
else:
|
||||
when defined(js):
|
||||
result = jsStartsWith(s, prefix)
|
||||
else:
|
||||
var i = 0
|
||||
while true:
|
||||
if prefix[i] == '\0': return true
|
||||
if s[i] != prefix[i]: return false
|
||||
inc(i)
|
||||
|
||||
func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} =
|
||||
## Returns true if `s` ends with `suffix`.
|
||||
##
|
||||
## JS backend uses native `String.prototype.endsWith`.
|
||||
runnableExamples:
|
||||
assert endsWith(cstring"Hello, Nimion", cstring"Nimion")
|
||||
assert not endsWith(cstring"Hello, Nimion", cstring"Hello")
|
||||
assert endsWith(cstring"Hello", cstring"")
|
||||
when nimvm:
|
||||
endsWithImpl(s, suffix)
|
||||
else:
|
||||
when defined(js):
|
||||
result = jsEndsWith(s, suffix)
|
||||
else:
|
||||
let slen = s.len
|
||||
var i = 0
|
||||
var j = slen - len(suffix)
|
||||
while i+j <% slen:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if suffix[i] == '\0': return true
|
||||
|
||||
func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} =
|
||||
## Semantically the same as `cmp(normalize($a), normalize($b))`. It
|
||||
## is just optimized to not allocate temporary strings. This should
|
||||
## NOT be used to compare Nim identifier names. use `macros.eqIdent`
|
||||
## for that. Returns:
|
||||
##
|
||||
## .. code-block::
|
||||
## 0 if a == b
|
||||
## < 0 if a < b
|
||||
## > 0 if a > b
|
||||
runnableExamples:
|
||||
assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0
|
||||
when nimvm:
|
||||
cmpIgnoreStyleImpl(a, b)
|
||||
else:
|
||||
when defined(js):
|
||||
cmpIgnoreStyleImpl(a, b)
|
||||
else:
|
||||
var i = 0
|
||||
var j = 0
|
||||
while true:
|
||||
while a[i] == '_': inc(i)
|
||||
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||
var aa = toLowerAscii(a[i])
|
||||
var bb = toLowerAscii(b[j])
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
inc(j)
|
||||
|
||||
func cmpIgnoreCase*(a, b: cstring): int =
|
||||
func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} =
|
||||
## Compares two strings in a case insensitive manner. Returns:
|
||||
##
|
||||
## .. code-block::
|
||||
## 0 if a == b
|
||||
## < 0 if a < b
|
||||
## > 0 if a > b
|
||||
runnableExamples:
|
||||
assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0
|
||||
assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0
|
||||
assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0
|
||||
when nimvm:
|
||||
cmpIgnoreCaseImpl(a, b)
|
||||
|
||||
# JS string has more operations that might warrant its own module:
|
||||
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||
else:
|
||||
func startsWith*(s, prefix: cstring): bool {.rtl, extern: "csuStartsWith".} =
|
||||
## Returns true if `s` starts with `prefix`.
|
||||
##
|
||||
## If `prefix == ""` true is returned.
|
||||
##
|
||||
## JS backend uses native `String.prototype.startsWith`.
|
||||
runnableExamples:
|
||||
assert startsWith(cstring"Hello, Nimion", cstring"Hello")
|
||||
assert not startsWith(cstring"Hello, Nimion", cstring"Nimion")
|
||||
|
||||
var i = 0
|
||||
while true:
|
||||
if prefix[i] == '\0': return true
|
||||
if s[i] != prefix[i]: return false
|
||||
inc(i)
|
||||
|
||||
func endsWith*(s, suffix: cstring): bool {.rtl, extern: "csuEndsWith".} =
|
||||
## Returns true if `s` ends with `suffix`.
|
||||
##
|
||||
## If `suffix == ""` true is returned.
|
||||
##
|
||||
## JS backend uses native `String.prototype.endsWith`.
|
||||
runnableExamples:
|
||||
assert endsWith(cstring"Hello, Nimion", cstring"Nimion")
|
||||
assert not endsWith(cstring"Hello, Nimion", cstring"Hello")
|
||||
|
||||
let slen = s.len
|
||||
var i = 0
|
||||
var j = slen - len(suffix)
|
||||
while i+j <% slen:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if suffix[i] == '\0': return true
|
||||
|
||||
func cmpIgnoreStyle*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreStyle".} =
|
||||
## Semantically the same as `cmp(normalize($a), normalize($b))`. It
|
||||
## is just optimized to not allocate temporary strings. This should
|
||||
## NOT be used to compare Nim identifier names. use `macros.eqIdent`
|
||||
## for that. Returns:
|
||||
##
|
||||
## .. code-block::
|
||||
## 0 if a == b
|
||||
## < 0 if a < b
|
||||
## > 0 if a > b
|
||||
runnableExamples:
|
||||
assert cmpIgnoreStyle(cstring"hello", cstring"H_e_L_Lo") == 0
|
||||
var i = 0
|
||||
var j = 0
|
||||
while true:
|
||||
while a[i] == '_': inc(i)
|
||||
while b[j] == '_': inc(j) # BUGFIX: typo
|
||||
var aa = toLowerAscii(a[i])
|
||||
var bb = toLowerAscii(b[j])
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
inc(j)
|
||||
|
||||
func cmpIgnoreCase*(a, b: cstring): int {.rtl, extern: "csuCmpIgnoreCase".} =
|
||||
## Compares two strings in a case insensitive manner. Returns:
|
||||
##
|
||||
## .. code-block::
|
||||
## 0 if a == b
|
||||
## < 0 if a < b
|
||||
## > 0 if a > b
|
||||
runnableExamples:
|
||||
assert cmpIgnoreCase(cstring"hello", cstring"HeLLo") == 0
|
||||
assert cmpIgnoreCase(cstring"echo", cstring"hello") < 0
|
||||
assert cmpIgnoreCase(cstring"yellow", cstring"hello") > 0
|
||||
|
||||
var i = 0
|
||||
while true:
|
||||
var aa = toLowerAscii(a[i])
|
||||
var bb = toLowerAscii(b[i])
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
else:
|
||||
when defined(js):
|
||||
cmpIgnoreCaseImpl(a, b)
|
||||
else:
|
||||
var i = 0
|
||||
while true:
|
||||
var aa = toLowerAscii(a[i])
|
||||
var bb = toLowerAscii(b[i])
|
||||
result = ord(aa) - ord(bb)
|
||||
if result != 0 or aa == '\0': break
|
||||
inc(i)
|
||||
|
||||
@@ -81,7 +81,7 @@ when defined(nimVmExportFixed):
|
||||
|
||||
include "system/inclrtl"
|
||||
import std/private/since
|
||||
from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl
|
||||
from std/private/strimpl import cmpIgnoreStyleImpl, cmpIgnoreCaseImpl, startsWithImpl, endsWithImpl
|
||||
|
||||
|
||||
const
|
||||
@@ -1530,11 +1530,7 @@ func startsWith*(s, prefix: string): bool {.rtl, extern: "nsuStartsWith".} =
|
||||
let a = "abracadabra"
|
||||
doAssert a.startsWith("abra") == true
|
||||
doAssert a.startsWith("bra") == false
|
||||
var i = 0
|
||||
while true:
|
||||
if i >= prefix.len: return true
|
||||
if i >= s.len or s[i] != prefix[i]: return false
|
||||
inc(i)
|
||||
startsWithImpl(s, prefix)
|
||||
|
||||
func endsWith*(s: string, suffix: char): bool {.inline.} =
|
||||
## Returns true if `s` ends with `suffix`.
|
||||
@@ -1562,12 +1558,7 @@ func endsWith*(s, suffix: string): bool {.rtl, extern: "nsuEndsWith".} =
|
||||
let a = "abracadabra"
|
||||
doAssert a.endsWith("abra") == true
|
||||
doAssert a.endsWith("dab") == false
|
||||
var i = 0
|
||||
var j = len(s) - len(suffix)
|
||||
while i+j >= 0 and i+j < s.len:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if i >= suffix.len: return true
|
||||
endsWithImpl(s, suffix)
|
||||
|
||||
func continuesWith*(s, substr: string, start: Natural): bool {.rtl,
|
||||
extern: "nsuContinuesWith".} =
|
||||
|
||||
@@ -4,13 +4,13 @@ func toLowerAscii*(c: char): char {.inline.} =
|
||||
else:
|
||||
result = c
|
||||
|
||||
template firstCharCaseSensitiveImpl(a, b: typed, aLen, bLen: int) =
|
||||
template firstCharCaseSensitiveImpl[T: string | cstring](a, b: T, aLen, bLen: int) =
|
||||
if aLen == 0 or bLen == 0:
|
||||
return aLen - bLen
|
||||
if a[0] != b[0]: return ord(a[0]) - ord(b[0])
|
||||
|
||||
template cmpIgnoreStyleImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) =
|
||||
# a, b are string or cstring
|
||||
template cmpIgnoreStyleImpl*[T: string | cstring](a, b: T,
|
||||
firstCharCaseSensitive: static bool = false) =
|
||||
let aLen = a.len
|
||||
let bLen = b.len
|
||||
var i = 0
|
||||
@@ -37,8 +37,8 @@ template cmpIgnoreStyleImpl*(a, b: typed, firstCharCaseSensitive: static bool =
|
||||
inc i
|
||||
inc j
|
||||
|
||||
template cmpIgnoreCaseImpl*(a, b: typed, firstCharCaseSensitive: static bool = false) =
|
||||
# a, b are string or cstring
|
||||
template cmpIgnoreCaseImpl*[T: string | cstring](a, b: T,
|
||||
firstCharCaseSensitive: static bool = false) =
|
||||
let aLen = a.len
|
||||
let bLen = b.len
|
||||
var i = 0
|
||||
@@ -51,3 +51,22 @@ template cmpIgnoreCaseImpl*(a, b: typed, firstCharCaseSensitive: static bool = f
|
||||
if result != 0: return
|
||||
inc i
|
||||
result = aLen - bLen
|
||||
|
||||
template startsWithImpl*[T: string | cstring](s, prefix: T) =
|
||||
let prefixLen = prefix.len
|
||||
let sLen = s.len
|
||||
var i = 0
|
||||
while true:
|
||||
if i >= prefixLen: return true
|
||||
if i >= sLen or s[i] != prefix[i]: return false
|
||||
inc(i)
|
||||
|
||||
template endsWithImpl*[T: string | cstring](s, suffix: T) =
|
||||
let suffixLen = suffix.len
|
||||
let sLen = s.len
|
||||
var i = 0
|
||||
var j = sLen - suffixLen
|
||||
while i+j >= 0 and i+j < sLen:
|
||||
if s[i+j] != suffix[i]: return false
|
||||
inc(i)
|
||||
if i >= suffixLen: return true
|
||||
|
||||
@@ -2,21 +2,25 @@ discard """
|
||||
targets: "c cpp js"
|
||||
"""
|
||||
|
||||
import cstrutils
|
||||
import std/cstrutils
|
||||
|
||||
|
||||
block tcstrutils:
|
||||
proc main() =
|
||||
let s = cstring "abcdef"
|
||||
doAssert s.startsWith("a")
|
||||
doAssert not s.startsWith("b")
|
||||
doAssert s.endsWith("f")
|
||||
doAssert not s.endsWith("a")
|
||||
doAssert s.startsWith("")
|
||||
doAssert s.endsWith("")
|
||||
|
||||
let a = cstring "abracadabra"
|
||||
doAssert a.startsWith("abra")
|
||||
doAssert not a.startsWith("bra")
|
||||
doAssert a.endsWith("abra")
|
||||
doAssert not a.endsWith("dab")
|
||||
doAssert a.startsWith("")
|
||||
doAssert a.endsWith("")
|
||||
|
||||
doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0
|
||||
doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0
|
||||
@@ -28,3 +32,7 @@ block tcstrutils:
|
||||
doAssert cmpIgnoreCase(cstring "", cstring "") == 0
|
||||
doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0
|
||||
doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0
|
||||
|
||||
|
||||
static: main()
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user