Cannot decode Caesar-Encrypted messages - go

I have to write a function for school that decodes Caesar-Encrypted messages. Our teacher gave us the code that encodes the messages, and asked us to write one based on the givenb function that decodes any encrypted message. (The key/shift wasn't given but was explicitly not 3 as in the the encode example, we should figure out ourselves. With online tools i know the key is 17 but for the purpose ofthe question i chose the given example with the known shift of 3)
The given Function with the Shift 3:
func main () {
var textN string = "Wenn man jetzt diesen Text Cäsar-Codieren möchte, dann macht man das so!" // Variable was given by tacher
var textC string = "Zhqq pdq mhwdw glhvhq Whbw Fävdu-Frglhuhq pöfkwh, gdqq pdfkw pdq gdv vr!" // Variable was given by tacher
fmt.Println(textN)
encode(textN)
decode(textC)
}
// The given Function with the shift 3:
func encode (text string){
var ergebnis string
for _,w:=range(text){
if w>='A' && w<='Z' {
if w+3>'Z'{
ergebnis += string((w+3)-'Z'+'A')
} else {
ergebnis += string(w+3)
}
} else if w>='a' && w<='z'{
if w+3>'z' {
ergebnis += string((w+3)-'z'+'a')
} else {
ergebnis += string(w+3)
}
} else {
ergebnis += string(w)
}
}
fmt.Println(ergebnis)
}
// My decode funtion with the "backwards shift" 3:
func decode (text string) {
var ergebnis string
for _,w:=range(text){
if w >='A' && w <='Z' {
if w-3 < 'A' {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string((w-3)+'Z'-'A')
} else {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string(w-3)
}
} else if w>='a' && w<='z'{
if w-3 < 'a' {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string((w-3)+'z'-'a')
} else {
// fmt.Println(string(w-3)) // Search for Mistakes made by me
ergebnis += string(w-3)
}
} else{
ergebnis += string(w)
}
}
fmt.Println(ergebnis)
}
Now the problem is: textN isn't equal to decode(textC), my code seems to fail at lowercase letters that shifted back 3 letters don't become the decoded letters they should be. I saw this at "z" and "x" and i dont have a clue why. I tried highering/lowering the shift but that didn't work, changed plusses and minusses and bigger lower signs. I don't know what to try and am thankful in advance.

there is one solution you can use, i can provide other slower one, but more interesting if you want.
func Chipher(input string, shift int) string {
bts := []rune(input)
var cursor *rune
// i em using it like this to remove repetition but its little advanced
// it may make you suspicious to teacher
shiftFn := func(start, end rune) bool {
r := *cursor
// not in range we cannot shift it
if r < start || r > end {
return false
}
res := start + (r-start+rune(shift))%(end-start)
if res < start {
res += end - start + 1
}
*cursor = res
return true
}
for i := range bts {
cursor = &bts[i]
// this is little trick, if one of expresions returns true, expressions
// after will not get executed as result would be true anyway
_ = shiftFn('a', 'z') || shiftFn('A', 'Z') || shiftFn('0', '9')
}
return string(bts)
}
now this is all beautiful but we have to do tests as well
func TestChipher(t *testing.T) {
testCases := []struct {
desc string
input, output string
shift int
}{
{
desc: "simple shift",
input: "abcd",
shift: 1,
output: "bcde",
},
{
desc: "negative shift",
input: "abcd",
shift: -1,
output: "zabc",
},
{
desc: "numbers",
input: "0123",
shift: 1,
output: "1234",
},
{
desc: "capital letters",
input: "ABCD",
shift: 1,
output: "BCDE",
},
{
desc: "big shift",
input: "ABCD",
shift: 1000,
output: "ABCD",
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
res := Chipher(tC.input, tC.shift)
if res != tC.output {
t.Errorf("\n%s :result\n%s :expected", res, tC.output)
}
})
}
}
hope you will learn new things from this

Related

Memoization error when converting naive recursive coin problem

I am attempting the following problem:
Two players start with a pile of coins, and each player has the choice of removing either one or two coins from the pile. The player who removes the last coin loses.
I have come up with the following naive, recursive implementation
(playgound):
func gameWinner(coinsRemaining int, currentPlayer string) string {
if coinsRemaining <= 0 {
return currentPlayer
}
var nextPlayer string
if currentPlayer == "you" {
nextPlayer = "them"
} else {
nextPlayer = "you"
}
if gameWinner(coinsRemaining-1, nextPlayer) == currentPlayer || gameWinner(coinsRemaining-2, nextPlayer) == currentPlayer {
return currentPlayer
} else {
return nextPlayer
}
}
func main() {
fmt.Println(gameWinner(4, "you")) // "them"
}
The above code works fine.
However, when I improve this solution by implementing memoization (see below, or on the playgound), I get the wrong answer.
func gameWinner(coinsRemaining int, currentPlayer string, memo map[int]string) string {
if coinsRemaining <= 0 {
return currentPlayer
}
var nextPlayer string
if currentPlayer == "you" {
nextPlayer = "them"
} else {
nextPlayer = "you"
}
if _, exists := memo[coinsRemaining]; !exists {
if gameWinner(coinsRemaining-1, nextPlayer, memo) == currentPlayer || gameWinner(coinsRemaining-2, nextPlayer, memo) == currentPlayer {
memo[coinsRemaining] = currentPlayer
} else {
memo[coinsRemaining] = nextPlayer
}
}
return memo[coinsRemaining]
}
func main() {
memo := make(map[int]string)
fmt.Println(gameWinner(4, "you", memo))
}
Any help as to why the second implementation is returning different values to the first would be greatly appreciated!
Your memoization is wrong: the winner does not only depend on the current number of coins, but also on whose turn it is. You need something like the following:
type state struct {
coinsRemaining int
currentPlayer string
}
memo := make(map[state]string)

Go and Fyne - Need response from dialog and enable/disable Submit button

Just starting to look at both Go and Fyne. After writing a test CRUD program using information obtained from examples, I need to solve the following:
I need an initial Dialog or similar in order to allow selection of an existing record or "new" to indicate a new record. My existing Dialog does not handle this adequately.
I need to be able to enable/disable the Submit button to allow or disallow update if the data has has-not changed.
The program compiles without error, however "go vet" and VsCode indicates (eg. for line):
{"Given Names:", arwWidgets[I_NDX_GIVEN]},
go vet shows:
ERROR: "unknown field 'Key' in struct literal of type widget.FormItem",
however, if I include a key, compiler fails.
Being new to both Go and Fyne, there are probably fundamental mistakes.
Test program is as follows:
package main
// Dependency: local directory "data".
import (
"errors"
"io/ioutil"
"log"
"os"
"strings"
"fyne.io/fyne"
"fyne.io/fyne/app"
"fyne.io/fyne/dialog"
"fyne.io/fyne/layout"
"fyne.io/fyne/widget"
)
const BY_SEP byte = byte('|')
const I_ARRAY_LEN int = 10
const I_NDX_GIVEN int = 0
const I_NDX_FAMILY int = 1
const I_NDX_TITLE int = 2
const I_NDX_ADDR1 int = 3
const I_NDX_ADDR2 int = 4
const I_NDX_ADDR3 int = 5
const I_NDX_STATE int = 6
const I_NDX_ZIP int = 7
const I_NDX_TELE1 int = 8
const I_NDX_TELE2 int = 9
var _arsOldData [I_ARRAY_LEN]string
var _arsNewData [I_ARRAY_LEN]string
var _tfDataHasChanged bool
var _sKey string
var _arwEntryWidgets [I_ARRAY_LEN]*widget.Entry
var _wApp fyne.App
var _wWindow fyne.Window
var _wModal widget.PopUp
var _wFormKeyEntry widget.Form
//-------------------------------------------------------------------------------
func main() {
log.Println("In fytest01")
_, err := os.Stat("./data/")
if err != nil {
log.Println("You need to create directory: 'data'")
os.Exit(1)
}
//fnReadData()
_wApp := app.New()
_wWindow := _wApp.NewWindow("Customer Details")
//_wFormKeyEntry := fnCreateKeyForm()
wFormMain := fnCreateMainForm()
//_wModal := widget.NewModalPopUp(_wFormKeyEntry, _wWindow.Canvas())
_wWindow.Resize(fyne.NewSize(500, 400))
_wWindow.CenterOnScreen()
_wWindow.SetContent(widget.NewVBox(
wFormMain,
widget.NewGroup("",
fyne.NewContainerWithLayout(layout.NewGridLayout(2),
widget.NewButton("Exit", func() {
_wApp.Quit()
}),
widget.NewButton("Submit", func() {
log.Println("Submit button pressed")
err := fnUpdateData()
if err == nil {
dialog.ShowInformation("Information", "Data was updated", _wWindow)
wEntryForKey := widget.NewEntry()
wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
wEntryForKey.OnChanged = func(sKey string) {
log.Println("Entered", sKey)
if len(sKey) == 4 {
_sKey = sKey
}
if len(_sKey) == 4 {
dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
fnReadData()
fnRefreshWidgetData()
}
}
dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
} else {
dialog.ShowError(err, _wWindow)
}
}),
))),
)
//fnShowKeyEntryDialog()
wEntryForKey := widget.NewEntry()
wEntryForKey.SetPlaceHolder("Enter Key (4) : ")
wEntryForKey.OnChanged = func(sKey string) {
log.Println("Entered", sKey)
if len(sKey) == 4 {
_sKey = sKey
}
if len(_sKey) == 4 {
dialog.ShowInformation("Information", "Key "+_sKey+" has been entered - press OK", _wWindow)
fnReadData()
fnRefreshWidgetData()
}
}
dialog.ShowCustom("Enter Customer Key", "OK", wEntryForKey, _wWindow)
_wWindow.ShowAndRun()
//_wModal.Show()
}
//-------------------------------------------------------------------------------
func fnCreateAllEntryWidgets() {
_arwEntryWidgets[I_NDX_GIVEN] = fnCreateSingleEntryWidget(I_NDX_GIVEN)
_arwEntryWidgets[I_NDX_FAMILY] = fnCreateSingleEntryWidget(I_NDX_FAMILY)
_arwEntryWidgets[I_NDX_TITLE] = fnCreateSingleEntryWidget(I_NDX_TITLE)
_arwEntryWidgets[I_NDX_ADDR1] = fnCreateSingleEntryWidget(I_NDX_ADDR1)
_arwEntryWidgets[I_NDX_ADDR2] = fnCreateSingleEntryWidget(I_NDX_ADDR2)
_arwEntryWidgets[I_NDX_ADDR3] = fnCreateSingleEntryWidget(I_NDX_ADDR3)
_arwEntryWidgets[I_NDX_STATE] = fnCreateSingleEntryWidget(I_NDX_STATE)
_arwEntryWidgets[I_NDX_ZIP] = fnCreateSingleEntryWidget(I_NDX_ZIP)
_arwEntryWidgets[I_NDX_TELE1] = fnCreateSingleEntryWidget(I_NDX_TELE1)
_arwEntryWidgets[I_NDX_TELE2] = fnCreateSingleEntryWidget(I_NDX_TELE2)
}
//-------------------------------------------------------------------------------
func fnCreateSingleEntryWidget(iNdxData int) *widget.Entry {
wEntry := widget.NewEntry()
wEntry.SetText(_arsOldData[iNdxData])
wEntry.OnChanged = func(sText string) {
_arsNewData[iNdxData] = sText
fnCheckIfDataHasChanged()
}
return wEntry
}
//-------------------------------------------------------------------------------
func fnCreateFormFields(arwWidgets [I_ARRAY_LEN]*widget.Entry) []*widget.FormItem {
return []*widget.FormItem{
{"Given Names:", arwWidgets[I_NDX_GIVEN]},
{"Family Name: ", arwWidgets[I_NDX_FAMILY]},
{"Title: ", arwWidgets[I_NDX_TITLE]},
{"Address Ln 1: ", arwWidgets[I_NDX_ADDR1]},
{" '' Ln 2: ", arwWidgets[I_NDX_ADDR2]},
{" '' Ln 3: ", arwWidgets[I_NDX_ADDR3]},
{" '' State ", arwWidgets[I_NDX_STATE]},
{" '' Zip: ", arwWidgets[I_NDX_ZIP]},
{"Telephone 1: ", arwWidgets[I_NDX_TELE1]},
{"Telephone 2: ", arwWidgets[I_NDX_TELE2]},
}
}
//-------------------------------------------------------------------------------
func fnCheckIfDataHasChanged() {
var tfChanged bool = false
for iNdxData := 0; !tfChanged && iNdxData < len(_arsOldData); iNdxData++ {
tfChanged = (_arsNewData[iNdxData] != _arsOldData[iNdxData])
}
if tfChanged != _tfDataHasChanged {
_tfDataHasChanged = tfChanged
if tfChanged {
// COULD NOT CREATE _wBtnSubmitMain AS A GLOBAL VARIABLE.
//_wBtnSubmitMain.Show()
//_wBtnSubmitMain.Enable()
} else {
//_wBtnSubmitMain.Disable()
//_wBtnSubmitMain.Hide()
}
}
}
//-------------------------------------------------------------------------------
func fnReadData() {
_tfDataHasChanged = false
log.Println("fnReadData: Key = " + _sKey)
var sData string
if len(_sKey) > 0 {
arbData, _ := ioutil.ReadFile("./data/" + _sKey)
if arbData != nil {
sData = string(arbData)
}
}
log.Println("fnReadData: sData = " + sData)
/* CLEAR OLD DATA */
for iNdxData := 0; iNdxData < I_ARRAY_LEN; iNdxData++ {
_arsOldData[iNdxData] = ""
}
/* POPULATE DATA IF ANY */
var iNdx1 int = 0
var iNdxData int = 0
var iLen int = len(sData)
for iNdx2 := 0; iNdx2 < len(sData); iNdx2++ {
if sData[iNdx2] == BY_SEP {
_arsOldData[iNdxData] = sData[iNdx1:iNdx2]
iNdx1 = iNdx2 + 1
iNdxData++
} else if iNdx2 == (iLen - 1) {
_arsOldData[iNdxData] = sData[iNdx1 : iNdx2+1]
}
}
for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
_arsNewData[iNdx] = _arsOldData[iNdx]
}
}
//-------------------------------------------------------------------------------
func fnUpdateData() error {
if !_tfDataHasChanged {
return errors.New("Data has not changed")
}
if len(_sKey) < 1 {
_sKey = "9999"
//dialog.ShowInformation("Information", "Default key of 9999 was used", _wWindow) // CAUSES ERROR
}
var sNewData string = ""
for iNdxData, sVal := range _arsNewData {
if strings.Index(sVal, "|") >= 0 {
sVal = strings.ReplaceAll(sVal, "|", ":")
}
if iNdxData != I_ARRAY_LEN-1 {
sNewData += sVal + string(BY_SEP)
} else {
sNewData += sVal
}
}
log.Println("New Data = " + sNewData)
var err error = ioutil.WriteFile("./data/"+_sKey, []byte(sNewData), 0644)
if err == nil {
for iNdxData := 0; iNdxData < len(_arsNewData); iNdxData++ {
_arsOldData[iNdxData] = _arsNewData[iNdxData]
}
fnCheckIfDataHasChanged()
}
return err
}
//-------------------------------------------------------------------------------
func fnCreateKeyForm() *widget.Form {
wEntryKey := widget.NewEntry()
return &widget.Form{
Items: []*widget.FormItem{
{"Key:", wEntryKey}},
OnSubmit: func() {
_sKey = wEntryKey.Text
log.Println("Key = " + _sKey)
fnReadData()
log.Println("Data has been read")
fnRefreshWidgetData()
_wFormKeyEntry.Hide()
//_wModal.Hide()
},
}
}
//-------------------------------------------------------------------------------
//func fnCreateMainWindow() {
// log.Println("Creating Main Window Form")
// wFormMain := fnCreateMainForm()
// log.Println("Creating Main Window Window")
// _wWindow.SetContent( //widget.NewVBox(
// wFormMain,
// )
//}
//-------------------------------------------------------------------------------
func fnCreateMainForm() *widget.Form {
log.Println("Create form1 widgets")
fnCreateAllEntryWidgets()
log.Println("Create form1 FormFields")
arwFormFields := fnCreateFormFields(_arwEntryWidgets)
log.Println("Creating Form1")
return &widget.Form{
Items: arwFormFields,
}
}
//-------------------------------------------------------------------------------
func fnRefreshWidgetData() {
for iNdx := 0; iNdx < I_ARRAY_LEN; iNdx++ {
_arwEntryWidgets[iNdx].SetText(_arsNewData[iNdx])
}
}
Can you just add a "New" button to the start window which fills in defaults then opens the main window. Does that make sense?
You create the Submit button by creating and passing it directly to SetContent. You need to save it in a variable, so that you can at some point call Disable() on it.
submitButton := widget.NewButton("Submit", func() {
log.Println("Submit button pressed")
...
})
_wWindow.SetContent(widget.NewVBox(
wFormMain,
widget.NewGroup("",
fyne.NewContainerWithLayout(layout.NewGridLayout(2),
widget.NewButton("Exit", func() {
_wApp.Quit()
}),
submitButton,
))),
)
...
if dataChanged {
submitButton.Enable()
} else {
submitButton.Disable()
}
I think the go vet message is saying you should name all the fields in your struct literal (though I get a different message to you using Go 1.13). Go allows you to add the values by order or by name - go vet is telling you that by name is safer (eg if fields are moved or inserted to the FormItem struct then your code would be broken).
Ie:
return []*widget.FormItem{
{ Text: "Given Names:", Widget: arwWidgets[I_NDX_GIVEN]},
...
Also it may simplify things to put all your global variables into a struct and then you can have "methods" on the struct. (There are a few reasons to avoid globals which you probably already know. I appreciate that this probably started as a simple test that has grown but it may be a good time to refactor.)
To change button options on toggle you need to use something like this:
buttonTitle := "Disable"
button := widget.NewButton(buttonTitle, nil)
changeButton := func() {
// here could be your logic
// how to disable/enable button
if button.Text == "Disable" {
buttonTitle = "Enable"
//button.Disable()
}
button.SetText(buttonTitle)
button.Refresh()
}
button.OnTapped = changeButton

Assign value to field in struct if empty

I have a struct defined
type data struct {
invitecode string
fname string
lname string
}
which I populate from retrieving form data after parsing
...
r.ParseForm()
new user := &data{
invitecode: r.FormValue("invitecode"),
fname: r.FormValue("fname")
lname: r.FormValue("lname")
}
I did like to check if the invitecode field obtained from the form is empty and if so, populate it by calling a function but if it is not, to populate it with the retrieved value (invitecode: if newUser.invitecode == "" {"Mr"} else {lnames.title},). I understand go doesn't have a tenary operator which I thought of using and reading the questions here, here, here & here implies using an if else statement but I can't seem to get it to work. Preferable, I am looking for a solution that check's while assigning a new variable. Trying the code below doesn't seem to work. Any help would be appreciated.
package main
import (
"fmt"
)
type data struct {
invitecode string
fname string
lname string
}
func main() {
var user data
newUser := map[string]string{"invitecode": "", "fname": "Dude", "lname": "Did"}
user = &data{
invitecode: if newUser.invitecode == "" {"Mr"} else {lnames.title},
fname: newUser.fname,
lname: newUser.lname,
}
fmt.Println(user)
}
You cannot use an if ... else statement inline like you would a ternary operator (or if/else statements) in other languages, you must simply do it procedurally:
user := &data{ /* ... */ }
if user.invitecode == "" {
user.invitecode = "Mr"
} else {
user.invitecode = lnames.title
}
Go does not have ternaries, nor can you do an inline if like you've shown in the code. You will have to do a normal if block:
user = &data{}
if newUser.inviteCode == "" {
user.invitecode = "Mr"
} else {
user.invitecode = lnames.title
}
And so on. You could extract this into a function:
func coalesce(args ...string) string {
for _,str := range args {
if str != "" {
return str
}
}
return ""
}
And use it like so:
user.invitecode = coalesce(lnames.title, "Mr")
Of course, if you deal with multiple types (not just strings), you'll need one such function for each type.

Algorithm: check for duplication in Swift array

Given an array of integers nums and an integer k. Find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the difference between i and j is at most k.
It is supposed to give me true, but it gives me false.
Any help, I appreciate it. Thank you so much.
class Solution
{
func containsNearbyDuplicate (nums: [Int], _ k: Int) -> Bool
{
var dict = [Int:Int]()
for i in 0..<nums.count
{
if dict[nums[i]] != nil
{
if dict.values.contains(nums[i]) && (i - dict[nums[i]]! <= k)
{
return true
}
else
{
dict[i] = nums[i]
}
}
}
return false
}
}
let test1 = Solution()
//var haha = [1,2,1,5,6,7,6,8,7,5]
//var haha = [1]
//var haha = [1,2]
//var haha = [1,2,3,5,6,8]
var haha = [-1,-1]
var result = test1.containsNearbyDuplicate(haha,1)
print(result)
You never add anything to dict:
func containsNearbyDuplicate (nums: [Int], _ k: Int) ->Bool
{
var dict = [Int:Int]()
for i in 0..<nums.count
{
if dict[nums[i]] != nil // This prevents anything to be added to dict
{
if dict.values.contains(nums[i]) && (i - dict[nums[i]]! <= k)
{
return true
}
else
{
dict[i] = nums[i] // This is never executed because of the above if above
}
}
}
return false
}
Try this one:
class Solution {
func containsNearbyDuplicate (nums: [Int], _ k: Int) ->Bool {
var dict = [Int:Int]()
for i in 0..<nums.count {
if let firstIndex = dict[nums[i]] where i - firstIndex <= k {
return true
}
dict[nums[i]] = i
}
return false
}
}

Sorting Strings by Character and Length

In my Android app, I am trying to sort Bus route tags in order 1, 2, 3..etc.
For that I am using this
Collections.sort(directions, Comparator { lhs, rhs ->
var obj1 = lhs.short_names.firstOrNull() ?: ""
var obj2 = rhs.short_names.firstOrNull() ?: ""
if (obj1 === obj2) {
obj1 = lhs.headsigns.firstOrNull() ?: ""
obj2 = rhs.headsigns.firstOrNull() ?: ""
if (obj1 === obj2) {
return#Comparator 0
}
obj1.compareTo(obj2)
} else {
obj1.compareTo(obj2)
}
The issue I am having is this sorts them, but will run into the issue of
1, 2, 3, 30, 31, 4, 5
How should I change this to get the correct ordering.
If you need just a simple number comparison you can do it like that.
directions.sortWith(Comparator { lhs, rhs ->
val i1 = lhs.toInt()
val i2 = rhs.toInt()
when {
i1 < i2 -> -1
i1 > i2 -> 1
else -> 0
}
})
As hotkey pointed out the code above can be replaced with almost identical implementation that looks much simplier.
directions.sortBy { it.toInt() }
The general version of this algorithm is called alphanum sorting and described in details here. I made a Kotlin port of this algorithm, which you can use. It's more complicated than what you need, but it will solve your problem.
class AlphanumComparator : Comparator<String> {
override fun compare(s1: String, s2: String): Int {
var thisMarker = 0
var thatMarker = 0
val s1Length = s1.length
val s2Length = s2.length
while (thisMarker < s1Length && thatMarker < s2Length) {
val thisChunk = getChunk(s1, s1Length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(s2, s2Length, thatMarker)
thatMarker += thatChunk.length
// If both chunks contain numeric characters, sort them numerically.
var result: Int
if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
// Simple chunk comparison by length.
val thisChunkLength = thisChunk.length
result = thisChunkLength - thatChunk.length
// If equal, the first different number counts.
if (result == 0) {
for (i in 0..thisChunkLength - 1) {
result = thisChunk[i] - thatChunk[i]
if (result != 0) {
return result
}
}
}
} else {
result = thisChunk.compareTo(thatChunk)
}
if (result != 0) {
return result
}
}
return s1Length - s2Length
}
private fun getChunk(string: String, length: Int, marker: Int): String {
var current = marker
val chunk = StringBuilder()
var c = string[current]
chunk.append(c)
current++
if (isDigit(c)) {
while (current < length) {
c = string[current]
if (!isDigit(c)) {
break
}
chunk.append(c)
current++
}
} else {
while (current < length) {
c = string[current]
if (isDigit(c)) {
break
}
chunk.append(c)
current++
}
}
return chunk.toString()
}
private fun isDigit(ch: Char): Boolean {
return '0' <= ch && ch <= '9'
}
}
To use this Comparator just call
directions.sortWith(AlphanumComparator())
If you don't need it to be coded in Kotlin you can just take an original Java version on Dave Koelle's page. And the Kotlin version of the algorithm can be also found on GitHub.

Resources