Skip to content

Instantly share code, notes, and snippets.

@wisq
Created January 19, 2018 23:55
Show Gist options
  • Save wisq/199b4f984c2c69235c5f6dbf63c396bf to your computer and use it in GitHub Desktop.
Save wisq/199b4f984c2c69235c5f6dbf63c396bf to your computer and use it in GitHub Desktop.
defmodule StrNext do
@character_ranges [
{'A', 'Z'},
{'a', 'z'},
{'0', '9'}
]
@characters Enum.map(@character_ranges, fn {a, z} ->
hd(a)..hd(z)
|> Enum.to_list()
end)
|> List.flatten()
def next(str) do
String.reverse(str)
|> next_string()
|> String.reverse()
end
def next_string(""), do: <<hd(@characters)>>
def next_string(<<byte, rest::bitstring>>) do
case next_character(byte) do
{c, true} -> <<c>> <> next_string(rest)
{c, false} -> <<c>> <> rest
end
end
def next_character(c) when c in @characters do
if (c + 1) in @characters do
{c + 1, false}
else
index = Enum.find_index(@characters, &(&1 == c))
if c = Enum.at(@characters, index + 1) do
{c, false}
else
{hd(@characters), true}
end
end
end
def next_character(c) do
{c, true}
end
end
# Passes these Ruby `String#succ` cases:
"abce" = StrNext.next("abcd")
"THX1139" = StrNext.next("THX1138")
"<<koalb>>" = StrNext.next("<<koala>>")
# Fails these Ruby `String#succ` cases:
# We don't restrict letters to letters and numbers to numbers.
# "2000aaa" = StrNext.next("1999zzz")
"1999zz0" = StrNext.next("1999zzz")
# Ditto.
# "AAAA0000" = StrNext.next("ZZZ9999")
"ZZaAAAA" = StrNext.next("ZZZ9999")
# We don't do punctuation.
# "**+" = StrNext.next("***")
"A***" = StrNext.next("***")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment