The title says it all, what is the easiest way to flip the endianness of a byte in Scala?
Edit: Here is an example of a hex string that can be converted to a List[Byte] for what I am talking about
"44[5e405f7b46d912b50ea59d0f0962ed9e251042a4b31208315c406a4aa962]ff" was not equal to "44[e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26]ff"
If you mean flipping low with high half-bits of a Byte:
(b: Byte) => (b >>> 4) + (b << 4)
If you want to flip every half-byte on a hex string I would grouped by 2 characters then flip the pairs before creating the string back again:
val input = "44[5e405f...".replaceAll("[^0-9a-f]","")
val expected = "44[e504f5...".replaceAll("[^0-9a-f]","")
// as suggested by #PaulDraper in the comments
input.grouped(2).map(_.reverse).mkString == expected
// or the verbose
val ab = "(.)(.)".r
input.grouped(2).map { case ab(a, b) => b ++ a }.mkString == expected
If your input is a List[Byte]:
val inputBytes = input.grouped(2).map(Integer.parseInt(_, 16).toByte)
val expectedBytes = expected.grouped(2).map(Integer.parseInt(_, 16).toByte)
inputBytes.map((b: Byte) => (b >>> 4) + (b << 4)).map(_.toByte).toSeq == expectedBytes.toSeq
Related
I'm trying to write the Jenkins Hash (http://burtleburtle.net/bob/hash/doobs.html) in Scala. This bit is tricky...
switch(len) /* all the case statements fall through */
{
case 11: c+=((ub4)k[10]<<24);
case 10: c+=((ub4)k[9]<<16);
case 9 : c+=((ub4)k[8]<<8);
/* the first byte of c is reserved for the length */
case 8 : b+=((ub4)k[7]<<24);
case 7 : b+=((ub4)k[6]<<16);
case 6 : b+=((ub4)k[5]<<8);
case 5 : b+=k[4];
case 4 : a+=((ub4)k[3]<<24);
case 3 : a+=((ub4)k[2]<<16);
case 2 : a+=((ub4)k[1]<<8);
case 1 : a+=k[0];
/* case 0: nothing left to add */
}
match statements don't fall through in Scala (which is an excellent design decision). So best way to do this I can think of is to have one if statement per case. I'm hoping someone can see a more pithy solution…
Something like this perhaps?
val (a,b,c) = k
.zipWithIndex
.foldLeft((0,0,0)) { case ((a,b,c), (v, index)) =>
index match {
case i if i < 4 => (a + (v << i*8), b, c)
case i if i < 8 => (a, b + (v << (i-4)*8), b, c)
case i => (a, b, c + (v << (i-7)*8))
}
}
I haven't tested the result, but this is one way to implement it. Drop and take the bytes of the array needed for each value. Also fold from right in order to rotate the rightmost value from 0 to 8 to 16 to 24.
Working with unsigned in JVM is a bit cumbersome and requires that we transform it to a wider data type, i.e. byte to int and int to long). Therefore we use longify to convert to byte to long. We also need to account for half the byte values being negative.
val longify = ((n: Byte) => n.toLong) andThen (n => if (n < 0) n + 256 else n)
def sum(m: Int, n: Int) =
k.drop(m).take(n).foldRight(0L)((b, s) => longify(b) + (s << 8))
val a = sum(0, 4)
val b = sum(4, 4)
val c = (sum(9, 3) << 8) + k.size
In this code where I'm attempting to xor the corresponding characters of two strings :
val s1 = "1c0111001f010100061a024b53535009181c";
val s2 = "686974207468652062756c6c277320657965";
val base64p1 = Base64.getEncoder().encodeToString(new BigInteger(s1, 16).toByteArray())
val base64p2 = Base64.getEncoder().encodeToString(new BigInteger(s2, 16).toByteArray())
val zs : IndexedSeq[(Char, Char)] = base64p1.zip(base64p2);
val xor = zs.foldLeft(List[Char]())((a: List[Char] , b: (Char, Char)) => ((Char)((b._1 ^ b._2))) :: a)
produces error :
Char.type does not take parameters
[error] val xor = zs.foldLeft(List[Char]())((a: List[Char] , b: (Char, Char)) => ((Char)((b._1 ^ b._2))) :: a)
How to xor the corresponding string char values and add them to List ?
What you're doing is can be simplified.
val xor = base64p1.zip(base64p2).map{case (a,b) => (a^b).toChar}.reverse
The result of the XOR op (^) is an Int. Just add .toChar to change it to a Char value.
But it looks like what you really want to do is XOR two large hex values that are represented as strings, and then return the result as a string. To do that all you need is...
val (v1, v2) = (BigInt(s1, 16), BigInt(s2, 16))
f"${v1 ^ v2}%x" // res0: String = 746865206b696420646f6e277420706c6179
You use java casting syntax. In scalla you cast like var.asInstanceOf[Type].
Should be (b._1 ^ b._2).asInstanceOf[Char].
I'd like to pad a vector of strings with a given value on all sides (i.e., top, bottom, right, left). For example, the following vector of strings:
1122
1122
3344
3344
should look like this:
000000
011220
011220
033440
033440
000000
Of course, this representation is purely for visual purposes and it is actually a Vector of strings.
I found I can accomplish this with the following code.
val v = Vector("1122", "1122", "3344", "3344")
Vector("000000") ++ (for { r <- v } yield "0" + r + "0") ++ Vector("000000")
However, I am fairly new to Scala and I feel I might be missing a better way to accomplish this. Is there a better way to pad a Vector of Strings in Scala with a given value?
Using jwvh's map approach with the * operator on String:
def repeat(len: Int, c: Char) = c.toString * len
def padLeftRight(s: String, len: Int, c: Char) = {
repeat(len - 1 - s.size, c) + s + c
}
def padSeq[S <: Seq[String]](xs: S, c: Char) = {
val len = xs.map(_.size).max + 2
val padded = repeat(len, c)
padded +: xs.map(padLeftRight(_, len, c)) :+ padded
}
Using padSeq with your example:
val v = Vector("1122", "1122", "3344", "3344")
val result = padSeq(v, '0')
gives:
Vector("000000", "011220", "011220", "033440", "033440", "000000")
If I have a sparse list of numbers:
Vector(1,3,7,8,9)
and I need to generate a string of a fixed size which replaces the 'missing' numbers with a given character that might look like this:
1.3...789
How would I do this in Scala?
Well, I'm not sure the range of the integers. So I'm assuming that they may not fit into a char and used a string. Try this:
val v = Vector(1,3,7,8,9)
val fixedStr = ( v.head to v.last )
.map( i => if (v.contains(i)) i.toString else "." )
.mkString
If you are only dealing with single digits then you may change the strings to chars in the above.
-- edit --
ok, so I couldn't help myself and addressed the issue of sparse vector and wanted to change it to use the sliding function. Figured it does no good sitting on my PC so sharing here:
v.sliding(2)
.map( (seq) => if (seq.size == 2) seq else seq ++ seq ) //normalize window to size 2
.foldLeft( new StringBuilder )( (sb, seq) => //fold into stringbuilder
seq match { case Seq(a,b) => sb.append(a).append( "." * (b - a - 1) ) } )
.append( v.last )
.toString
One way to do this is using sliding and pattern matching:
def mkNiceString(v: Vector[Int]) = {
v.sliding(2).map{
case Seq(a) => ""
case Seq(a,b) =>
val gap = b-a;
a.toString + (if(gap>1) "." * (gap-1) else "")
}.mkString + v.last
}
In the REPL:
scala> mkNiceString(Vector(1,3,7,8,9,11))
res22: String = 1.3...789.11
If the vector is sparse, this will be more efficient than checking the range between the first and the last number.
def padVector(numbers: Vector[Int], placeHolder: String) = {
def inner(nums: Vector[Int], prevNumber: Int, acc: String) : String =
if (nums.length == 0) acc
else (nums.head - prevNumber) match {
// the difference is 1 -> no gap between this and previous number
case 1 => inner(nums.tail, nums.head, acc + nums.head)
// gap between numbers -> add placeholder x times
case x => inner(nums.tail, nums.head, acc + (placeHolder * (x-1)) + nums.head)
}
if (numbers.length == 0) ""
else inner(numbers.tail, numbers.head, numbers.head.toString)
}
Output:
scala> padVector(Vector(1,3,7,8,9), ".")
res4: String = 1.3...789
I want to convert a char to an int value.
I am a bit puzzled by the way toInt works.
println(("123").toList) //List(1, 2, 3)
("123").toList.head // res0: Char = 1
("123").toList.head.toInt // res1: Int = 49 WTF??????
49 pops up randomly for no reason.
How do you convert a char to int the right way?
For simple digit to int conversions there is asDigit:
scala> "123" map (_.asDigit)
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
Use Integer.parseInt("1", 10). Note that the 10 here is the radix.
val x = "1234"
val y = x.slice(0,1)
val z = Integer.parseInt(y)
val z2 = y.toInt //equivalent to the line above, see #Rogach answer
val z3 = Integer.parseInt(y, 8) //This would give you the representation in base 8 (radix of 8)
49 does not pop up randomly. It's the ascii representation of "1". See http://www.asciitable.com/
.toInt will give you the ascii value. It's probably easiest to write
"123".head - '0'
If you want to handle non-numeric characters, you can do
c match {
case c if '0' <= c && c <= '9' => Some(c - '0')
case _ => None
}
You can also use
"123".head.toString.toInt