Support all digit chars on JS and Native #KT-46002
This commit is contained in:
@@ -18,6 +18,10 @@ private object Digit {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the largest element in [array] smaller or equal to the specified [needle],
|
||||
* or -1 if [needle] is smaller than the smallest element in [array].
|
||||
*/
|
||||
internal fun binarySearchRange(array: IntArray, needle: Int): Int {
|
||||
var bottom = 0
|
||||
var top = array.size - 1
|
||||
@@ -36,12 +40,20 @@ internal fun binarySearchRange(array: IntArray, needle: Int): Int {
|
||||
return middle - (if (needle < value) 1 else 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer from 0..9 indicating the digit this character represents,
|
||||
* or -1 if this character is not a digit.
|
||||
*/
|
||||
internal fun Char.digitToIntImpl(): Int {
|
||||
val ch = this.code
|
||||
val index = binarySearchRange(Digit.rangeStart, ch)
|
||||
val diff = ch - Digit.rangeStart[index]
|
||||
return if (diff < 10) diff else -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if this character is a digit.
|
||||
*/
|
||||
internal fun Char.isDigitImpl(): Boolean {
|
||||
val ch = this.code
|
||||
val index = binarySearchRange(Digit.rangeStart, ch)
|
||||
val high = Digit.rangeStart[index] + 9
|
||||
return ch <= high
|
||||
return digitToIntImpl() >= 0
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ private object Digit {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the largest element in [array] smaller or equal to the specified [needle],
|
||||
* or -1 if [needle] is smaller than the smallest element in [array].
|
||||
*/
|
||||
internal fun binarySearchRange(array: IntArray, needle: Int): Int {
|
||||
var bottom = 0
|
||||
var top = array.size - 1
|
||||
@@ -36,12 +40,20 @@ internal fun binarySearchRange(array: IntArray, needle: Int): Int {
|
||||
return middle - (if (needle < value) 1 else 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer from 0..9 indicating the digit this character represents,
|
||||
* or -1 if this character is not a digit.
|
||||
*/
|
||||
internal fun Char.digitToIntImpl(): Int {
|
||||
val ch = this.code
|
||||
val index = binarySearchRange(Digit.rangeStart, ch)
|
||||
val diff = ch - Digit.rangeStart[index]
|
||||
return if (diff < 10) diff else -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if this character is a digit.
|
||||
*/
|
||||
internal fun Char.isDigitImpl(): Boolean {
|
||||
val ch = this.code
|
||||
val index = binarySearchRange(Digit.rangeStart, ch)
|
||||
val high = Digit.rangeStart[index] + 9
|
||||
return ch <= high
|
||||
return digitToIntImpl() >= 0
|
||||
}
|
||||
|
||||
@@ -152,5 +152,8 @@ internal actual fun digitOf(char: Char, radix: Int): Int = when {
|
||||
char >= '0' && char <= '9' -> char - '0'
|
||||
char >= 'A' && char <= 'Z' -> char - 'A' + 10
|
||||
char >= 'a' && char <= 'z' -> char - 'a' + 10
|
||||
else -> -1
|
||||
char < '\u0080' -> -1
|
||||
char >= '\uFF21' && char <= '\uFF3A' -> char - '\uFF21' + 10 // full-width latin capital letter
|
||||
char >= '\uFF41' && char <= '\uFF5A' -> char - '\uFF41' + 10 // full-width latin small letter
|
||||
else -> char.digitToIntImpl()
|
||||
}.let { if (it >= radix) -1 else it }
|
||||
|
||||
@@ -33,6 +33,8 @@ public fun Char.digitToInt(): Int {
|
||||
* - [isDigit] is `true` for the Char and the Unicode decimal digit value of the character is less than the specified [radix]. In this case the decimal digit value is returned.
|
||||
* - The Char is one of the uppercase Latin letters 'A' through 'Z' and its [code] is less than `radix + 'A'.code - 10`. In this case, `this.code - 'A'.code + 10` is returned.
|
||||
* - The Char is one of the lowercase Latin letters 'a' through 'z' and its [code] is less than `radix + 'a'.code - 10`. In this case, `this.code - 'a'.code + 10` is returned.
|
||||
* - The Char is one of the fullwidth Latin capital letters '\uFF21' through '\uFF3A' and its [code] is less than `radix + 0xFF21 - 10`. In this case, `this.code - 0xFF21 + 10` is returned.
|
||||
* - The Char is one of the fullwidth Latin small letters '\uFF41' through '\uFF5A' and its [code] is less than `radix + 0xFF41 - 10`. In this case, `this.code - 0xFF41 + 10` is returned.
|
||||
*
|
||||
* @sample samples.text.Chars.digitToInt
|
||||
*/
|
||||
@@ -65,6 +67,8 @@ public fun Char.digitToIntOrNull(): Int? {
|
||||
* - [isDigit] is `true` for the Char and the Unicode decimal digit value of the character is less than the specified [radix]. In this case the decimal digit value is returned.
|
||||
* - The Char is one of the uppercase Latin letters 'A' through 'Z' and its [code] is less than `radix + 'A'.code - 10`. In this case, `this.code - 'A'.code + 10` is returned.
|
||||
* - The Char is one of the lowercase Latin letters 'a' through 'z' and its [code] is less than `radix + 'a'.code - 10`. In this case, `this.code - 'a'.code + 10` is returned.
|
||||
* - The Char is one of the fullwidth Latin capital letters '\uFF21' through '\uFF3A' and its [code] is less than `radix + 0xFF21 - 10`. In this case, `this.code - 0xFF21 + 10` is returned.
|
||||
* - The Char is one of the fullwidth Latin small letters '\uFF41' through '\uFF5A' and its [code] is less than `radix + 0xFF41 - 10`. In this case, `this.code - 0xFF41 + 10` is returned.
|
||||
*
|
||||
* @sample samples.text.Chars.digitToIntOrNull
|
||||
*/
|
||||
|
||||
@@ -80,17 +80,21 @@ class CharTest {
|
||||
}
|
||||
}
|
||||
|
||||
for (char in 'A'..'Z') {
|
||||
val digit = 10 + (char - 'A')
|
||||
val lower = char.lowercaseChar()
|
||||
val letterRanges = listOf('A'..'Z', '\uFF21'..'\uFF3A')
|
||||
|
||||
for (radix in digit + 1..36) {
|
||||
testEquals(digit, char, radix)
|
||||
testEquals(digit, lower, radix)
|
||||
}
|
||||
for (radix in 2..digit) {
|
||||
testFails(char, radix)
|
||||
testFails(lower, radix)
|
||||
for (range in letterRanges) {
|
||||
for (char in range) {
|
||||
val digit = 10 + (char - range.first)
|
||||
val lower = char.lowercaseChar()
|
||||
|
||||
for (radix in digit + 1..36) {
|
||||
testEquals(digit, char, radix)
|
||||
testEquals(digit, lower, radix)
|
||||
}
|
||||
for (radix in 2..digit) {
|
||||
testFails(char, radix)
|
||||
testFails(lower, radix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user