Hex String to Int,Short and Long in Scala - scala

Just can't find a way to transform an Hex String to a number (Int, Long, Short) in Scala.
Is there something like "A".toInt(base)?

You can use the Java libs:
val number = Integer.parseInt("FFFF", 16)
> number: Int = 65535
Or if you are feeling sparky :-):
implicit def hex2int (hex: String): Int = Integer.parseInt(hex, 16)
val number: Int = "CAFE" // <- behold the magic
number: Int = 51966
Also, if you aren't specifically trying to parse a String parameter into hex, note that Scala directly supports hexadecimal Integer literals. In this case:
val x = 0xCAFE
> x: Int = 51966
Isn't Scala wonderful? :-)

7zark7 answer is correct, but I want to make some additions.
Implicit from String to Int can be dangerous. Instead you can use implicit conversion to wrapper and call parsing explicitly:
class HexString(val s: String) {
def hex = Integer.parseInt(s, 16)
}
implicit def str2hex(str: String): HexString = new HexString(str)
val num: Int = "CAFE".hex

What about a one-liner?
def hexToInt(s: String): Int = {
s.toList.map("0123456789abcdef".indexOf(_)).reduceLeft(_ * 16 + _)
}
scala> hexToInt("cafe")
res0: Int = 51966
And to answer your second item:
Is there something like "A".toInt(base)?
Yes, still as a one-liner:
def baseToInt(s: String, base: String): Int = {
s.toList.map(base.indexOf(_)).reduceLeft(_ * base.length + _)
}
scala> baseToInt("1100", "01")
res1: Int = 12

Anyone wanting to convert a UUID from hex to a decimal number can borrow from Benoit's answer and use BigDecimal for the job:
scala> "03cedf84011dd11e38ff0800200c9a66".toList.map(
| "0123456789abcdef".indexOf(_)).map(
| BigInt(_)).reduceLeft( _ * 16 + _)
res0: scala.math.BigInt = 5061830576017519706280227473241971302
Or more generally:
def hex2dec(hex: String): BigInt = {
hex.toLowerCase().toList.map(
"0123456789abcdef".indexOf(_)).map(
BigInt(_)).reduceLeft( _ * 16 + _)
}
def uuid2dec(uuid: UUID): BigInt = {
hex2dec(uuid.toString.replace("-",""))
}
Then:
scala> import java.util.UUID
scala> val id = UUID.fromString("3CEDF84-011D-D11E-38FF-D0800200C9A66")
id: java.util.UUID = 03cedf84-011d-d11e-38ff-0800200c9a66
scala> uuid2dec(id)
res2: BigInt = 5061830576017519706280227473241971302
One practical application for this is encoding the UUID in a barcode, where Code128 produces a shorter barcode for all digits than it does with alphanumeric strings. See notes about subtype "128A" on http://en.wikipedia.org/wiki/Code128#Subtypes.

For Long and Short, it is also possible to use the Java methods directly like
Long2long(java.lang.Long.valueOf(hexString, 16))
where Long2long can be even be omitted in some cases.

Related

declare val with a loop in scala

Im learning scala and Im wondering if it's possible to declare a val in the following way :
val aLotOfZero : String = for(i<-0 to 63) {"0"}
instead of
var tmp : String = ""
for(i<-0 to 63)
{
tmp += "0"
}
val aLotOfZero : String = tmp
And if it's possible to replace the "0" by other stuff.
Thanks you
If what you want is to build a String value with n zeroes, you could use a for yielding the character 0 and then making the returning Vectorto a string using mkString as follows:
scala> val aLotOfZeroes: String = (for (i <- 0 to 63) yield "0").mkString
aLotOfZeroes: String = 0000000000000000000000000000000000000000000000000000000000000000
And then, you could generalize it by adding a parameter likewise:
scala> def aLotOfZeroes(n: Int): String = (for (i <- 0 to n) yield "0").mkString
aLotOfZeroes: (n: Int)String
scala> aLotOfZeroes(10)
res2: String = 00000000000
scala> val zeroes: String = aLotOfZeroes(10)
zeroes: String = 00000000000
scala> zeroes
res3: String = 00000000000
Also, from #dividebyzero's comment, you can use *:
scala> "0" * 64
res13: String = 0000000000000000000000000000000000000000000000000000000000000000
And define:
scala> def aLotOfZeroes: Int => String = "0" * _
aLotOfZeroes: Int => String
scala> aLotOfZeroes(10)
res16: String = 0000000000

scala string interpolation with a variable length

I use scala f string interpolator as follows:
def format(id: Int) = f"A$id%04d"
format(21) // A0021
However, I would like to be able to define a length once and for all (before fixed to 4), and get a function that it is going to format the string with that length.
So, instead of having
def format(length: Int, id: Int) = ???
f(5, 21) // A00021
I would like to have this:
def format(length: Int)(id: Int) = ???
val f = format(5)
f(21) // A00021
How can I implement this using scala f interpolator or other?
Update
I was not looking for such a solution involving the compiler at runtime, but I appreciate som-snytt's answer. Here there is a working solution based on his answer:
import scala.tools.reflect._,scala.reflect.runtime._,universe._
def defFormat(length: Int): Int => String = {
val code = raw"""(i: Int) => f"A$$i%0${length}d""""
tb.eval(tb.parse(code)).asInstanceOf[Int => String]
}
val format = defFormat(length = 5)
format(21)
scala> def format(n: Int)(i: Int) =
| f"A%%0${n}d" format i
format: (n: Int)(i: Int)String
scala> format(5) _
res0: Int => String = <function1>
scala> .apply(21)
res1: String = A00021
Edit:
scala> import scala.tools.reflect._,scala.reflect.runtime._,universe._
import scala.tools.reflect._
import scala.reflect.runtime._
import universe._
scala> val tb = currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#2d10e0b1
scala> def f(n: Int)(i: Int): String = {
| val code = raw"""f"A$${$i}%0${n}d""""
| tb.eval(tb.parse(code)).asInstanceOf[String]
| }
f: (n: Int)(i: Int)String
scala> val g = f(5) _
g: Int => String = <function1>
scala> g(21)
res9: String = A00021
That doesn't actually help much. You really want to
scala> tb.typecheck(tb.parse(code))
scala.tools.reflect.ToolBoxError: reflective typecheck has failed: illegal conversion character 'k'
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:178)
which throws if the format is bad.
scala> val code = raw"""(i: Int) => f"A$${i}%k0${10}d""""
code: String = (i: Int) => f"A${i}%k010d"
scala> tb.typecheck(tb.parse(code))
scala.tools.reflect.ToolBoxError: reflective typecheck has failed: illegal conversion character 'k'
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:178)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$typecheck$1.apply(ToolBoxFactory.scala:170)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$11.apply(ToolBoxFactory.scala:148)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$11.apply(ToolBoxFactory.scala:148)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$9.apply(ToolBoxFactory.scala:138)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$9.apply(ToolBoxFactory.scala:138)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$withContext$1$1.apply(ToolBoxFactory.scala:139)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$withContext$1$1.apply(ToolBoxFactory.scala:139)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$7.apply(ToolBoxFactory.scala:137)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1$$anonfun$7.apply(ToolBoxFactory.scala:137)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1.apply(ToolBoxFactory.scala:148)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$transformDuringTyper$1.apply(ToolBoxFactory.scala:121)
at scala.reflect.internal.Trees$class.wrappingIntoTerm(Trees.scala:1716)
at scala.reflect.internal.SymbolTable.wrappingIntoTerm(SymbolTable.scala:16)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.withWrapping$1(ToolBoxFactory.scala:120)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.transformDuringTyper(ToolBoxFactory.scala:121)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.typecheck(ToolBoxFactory.scala:169)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$typecheck$2.apply(ToolBoxFactory.scala:375)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$typecheck$2.apply(ToolBoxFactory.scala:367)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(ToolBoxFactory.scala:355)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:355)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.typecheck(ToolBoxFactory.scala:367)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.typecheck(ToolBoxFactory.scala:27)
... 32 elided
scala> val code = raw"""(i: Int) => f"A$${i}%0${10}d""""
code: String = (i: Int) => f"A${i}%010d"
scala> tb.typecheck(tb.parse(code))
res19: tb.u.Tree =
((i: Int) => ({
val arg$macro$9: Int = i;
new scala.collection.immutable.StringOps("A%010d").format(arg$macro$9)
}: String))
You can't do it using f because its whole point is to make sure it can check the format string for type errors, so the format string has to be static. f could support this scenario explicitly, but it doesn't.
You could make format a macro, but this seems like an overkill. Not to mention that it would have to be defined in a separate module, which looks very inconvenient for this scenario.

Convert Any to Double using asInstanceOf?

Is there a supported way to achieve a conversion of any numeric type to a double. E.g.
val i = 12345
val f = 1234.5F
val d = 1234.5D
val arr = Array[Any](i,f,d)
val anotherD = arr(0).asInstanceOf[Numeric].toDouble
Naturally the above code is not correct as given - since Numeric requires Type arguments.
scala> val i = 12345
i: Int = 12345
scala> val f = 1234.5F
f: Float = 1234.5
scala> val d = 1234.5D
d: Double = 1234.5
scala> val arr = Array[Any](i,f,d)
arr: Array[Any] = Array(12345, 1234.5, 1234.5)
scala> val anotherD = arr(0).asInstanceOf[Numeric].toDouble
<console>:11: error: type Numeric takes type parameters
val anotherD = arr(0).asInstanceOf[Numeric].toDouble
Now I realize the above may be achieved via match/case , along the following lines:
(a, e) match {
case (a : Double, e : Double) =>
Math.abs(a - e) <= CompareTol
case (a : Float, e : Float) =>
Math.abs(a - e) <= CompareTol
.. etc
But I was wondering if there were a means to more compactly express the operation. This code is within TEST classes and efficiency is not an important criterion. Specifically: reflection calls are OK. Thanks.
I assume you are on the JVM. The Number class does like what you want to achieve with the doubleValue method:
val arr = Array[Number](i,f,d)
val ds = arr.map(_.doubleValue())
This is horrible, and probably not efficient, but it works (on your example) :p
scala> import scala.language.reflectiveCalls
import scala.language.reflectiveCalls
scala> arr.map(_.asInstanceOf[{ def toDouble: Double }].toDouble)
res2: Array[Double] = Array(12345.0, 1234.5, 1234.5)

Any way to DRY up these functions that convert numbers with defaults?

I have a number of functions like this:
// Convert a string to integer, defaulting to 0 if it fails
def safeToInt(s: String): Int = try {
s.toInt
} catch {
case _: NumberFormatException => 0
}
// Convert a string to long, defaulting to 0 if it fails
def safeToLong(s: String): Long = try {
s.toLong
} catch {
case _: NumberFormatException => 0
}
// Convert a string to double, defaulting to 0 if it fails
def safeToDouble(s: String): Double = try {
s.toDouble
} catch {
case _: NumberFormatException => 0
}
Any way to make these cleaner? They essentially all do the same thing apart from one line.
You can take advantage of Numeric to avoid duplicating the zero.
import scala.util.Try
def safeToNumeric[A: Numeric](f: String => A)(s: String): A =
Try(f(s)).getOrElse(implicitly[Numeric[A]].zero)
val safeToInt = safeToNumeric(_.toInt)(_)
val safeToLong = safeToNumeric(_.toLong)(_)
val safeToDouble = safeToNumeric(_.toDouble)(_)
safeToInt("4") // 4
safeToDouble("a") // 0.0
Unfortunately Numeric doesn't give you the parsing method as well, but you can create the appropriate type class yourself ...
case class Parser[A](parse : String => A)
implicit val intParser = Parser(_.toInt)
implicit val longParser = Parser(_.toLong)
implicit val doubleParser = Parser(_.toDouble)
... and then you can write a single method that works for all of the types.
def safeTo[A: Parser : Numeric](s: String): A =
Try(implicitly[Parser[A]].parse(s))
.getOrElse(implicitly[Numeric[A]].zero)
safeTo[Int]("4") // 4
safeTo[Double]("a") // 0.0
You can use scala.util.Try
import util.Try
// Convert a string to integer, defaulting to 0 if it fails
def safeToInt(s: String): Int = Try(s.toInt).getOrElse(0)
// Convert a string to long, defaulting to 0 if it fails
def safeToLong(s: String): Long = Try(s.toLong).getOrElse(0L)
// Convert a string to double, defaulting to 0 if it fails
def safeToDouble(s: String): Double = Try(s.toDouble).getOrElse(0.0)
Although Chris Martin's answer is probably the most sophisticated, it is quite complex. You can encapsulate the "try something, or else get me the default" by using a function that returns a function.
import scala.util.Try
def safeConverter[A](convert: String => A, default: A) = { input: String =>
Try(convert(input)).getOrElse(default)
}
val safeToInt = safeConverter(_.toInt, 0)
val safeToLong = safeConverter(_.toLong, 0L)
val safeToDouble = safeConverter(_.toDouble, 0.0)
safeToInt("334") // Returns 334
safeToInt("this is not a number") // Returns 0
converter returns a function that performs conversion of a String with a default in case an exception is thrown.
You can use this converter for any conversion that potentially throws an exception, not just numeric values.

Type safe String interpolation in Scala

Inspired by this, I was wondering if we can have type-safe string interpolations in Scala (maybe using macros)?
For example, I want to have something like this
def a[A] = ???
val greetFormat = f"Hi! My name is ${a[String]}. I am ${a[Int]} years old"
greetFormat.format("Rick", 27) // compiles
//greetFormat.format("Rick", false) // does not compile
//greetFormat.format(27, "Rick") // does not compile
//greetFormat.format("Rick", 27, false) // does not compile
//greetFormat.format("Rick") // does not compile or is curried?
The f string interpolator is already implemented with a macro.
This can be demonstrated inside of the REPL:
scala> val b = "not a number"
b: String = not a number
scala> f"$b%02d"
<console>:9: error: type mismatch;
found : String
required: Int
f"$b%02d"
^
Just wrap it in a function.
def greet(name: String, age: Int) = s"Hi! My name is $name. I am $age years old"
You can supply implicits to the f-interpolator:
scala> case class A(i: Int)
defined class A
scala> implicit def atoi(a: A): Int = a.i
warning: there were 1 feature warning(s); re-run with -feature for details
atoi: (a: A)Int
scala> f"${A(42)}%02d"
res5: String = 42
See also Travis Brown's examples and solution for using regex group names in extractions. It took me about a minute to steal that great idea.
"a123bc" match {
case res # xr"(?<c>a)(?<n>\d+)(?<s>bc)" => assert {
res.c == 'a' && res.n == 123 && res.s == "bc"
}
}
For the record, on the composition side, I would like:
val a = A(Rick, 42)
val greeter = f"Hi! My name is $_. I am ${_}%d years old"
greeter(a, a)
But it was deemed too much for the poor underscore. You'll have to write the function as in the other answer.
Your form, in which your macro sees "${a[Int]}" and writes a function with an Int param, doesn't look hard to implement.
Other features of the f-interpolator include other static error checking:
scala> f"$b%.02d"
<console>:19: error: precision not allowed
f"$b%.02d"
^
and support for Formattable:
scala> val ff = new Formattable { def formatTo(fmtr: Formatter, flags: Int, width: Int, precision: Int) = fmtr.format("%s","hello, world") }
ff: java.util.Formattable = $anon$1#d2e6b0b
scala> f"$ff"
res6: String = hello, world
A quick macro might emit (i: Int) => f"${ new Formattable {...} }".