The Crystal Programming Language Forum

Any other way to make string alphanumeric?

Having fun with deleting non-alphanumeric character from my string :slight_smile:
My first code was this:

def make_alphanumeric(name)
    safe_name =""
    name.each_char do |ch|
      if ch.alphanumeric?
        safe_name +=ch
      end
    end
    safe_name
end

my second code:

def make_alphanumeric(name)
    safe_name =""
    name.each_char {|x| safe_name +=x if x.alphanumeric? }
    safe_name
end

and my third code:

def make_alphanumeric(name)
    (name.chars.select! {|x| x.alphanumeric? }).join
end

I think we also can do it with regex but I don’t know how,
any way I like the last one :slight_smile:

name.gsub /[^\w\d]/, "". Replace any non word/digit characters with an empty string.

1 Like

nice your version is shorter,
I think it is the shortest way we can do this :slight_smile:
thank you.

Also remember there’s String.build { |str| str << "1"; str << "2" }. That’s one of the most efficient ways to build a string. Using += will create a lot of intermediate strings and it will be very, very slow.

1 Like

@Blacksmoke16
your code will delete Unicode characters.

pp 'ß'.alphanumeric?
pp "ß".gsub /[^\w\d]/,""

In that case

def alphanum(str : String)
  String.build do |str_io|
    str.each_char.select(&.alphanumeric?).join str_io
  end
end

might be your best bet?

is this faster than

def make_alphanumeric(name)
    (name.chars.select! {|x| x.alphanumeric? }).join
end

IDK, you’d have to benchmark it.

EDIT: I did it.

require "benchmark"

def alphanum(str : String)
  String.build do |str_io|
    str.each_char.select(&.alphanumeric?).join str_io
  end
end

def make_alphanumeric(name)
  (name.chars.select! { |x| x.alphanumeric? }).join
end

Benchmark.ips do |x|
  x.report("one") do
    alphanum "aaa!@^ß(*98ß68as0df"
  end

  x.report("two") do
    make_alphanumeric "aaa!@^ß(*98ß68as0df"
  end
end
one   2.77M (361.13ns) (± 2.79%)  288B/op        fastest
two   2.36M (423.79ns) (± 3.75%)  321B/op   1.17× slower

Slightly faster with bit better memory usage yea.

1 Like

Thank you, my results was the same:

one   2.38M (420.53ns) (± 1.50%)  288B/op        fastest
two   2.13M (468.43ns) (± 1.32%)  320B/op   1.11× slower
...
one   2.24M (446.00ns) (± 7.10%)  288B/op        fastest
two   2.17M (461.15ns) (± 4.35%)  320B/op   1.03× slower
...
one   2.46M (405.76ns) (± 0.64%)  288B/op        fastest
two   2.22M (450.82ns) (± 0.71%)  320B/op   1.11× slower

require "benchmark"

def alphanum(str : String)
  String.build do |str_io|
    str.each_char.select(&.alphanumeric?).join str_io
  end
end

def make_alphanumeric(name)
  (name.chars.select! { |x| x.alphanumeric? }).join
end

def manual(name)
  name.gsub { |c| c.alphanumeric? ? c : nil }
end

Benchmark.ips do |x|
  x.report("alphanum") do
    alphanum "aaa!@^ß(*98ß68as0df"
  end

  x.report("make_alphanumeric") do
    make_alphanumeric "aaa!@^ß(*98ß68as0df"
  end

  x.report("manual") do
    manual "aaa!@^ß(*98ß68as0df"
  end
end

Output:

         alphanum   2.46M (406.81ns) (± 7.63%)  288B/op   1.57× slower
make_alphanumeric   2.36M (424.59ns) (± 3.09%)  321B/op   1.63× slower
           manual   3.85M (259.78ns) (± 2.62%)  144B/op        fastest
3 Likes

another faster solution :slight_smile: