Scalaでは、この方法でバイト配列を宣言できます
val ipaddr: Array[Byte] = Array(192.toByte, 168.toByte, 1.toByte, 9.toByte)
これは冗長すぎます。 Javaのと同様に、バイト配列を宣言する簡単な方法はありますか
byte[] ipaddr = {192, 168, 1, 1};
以下は、文字列の.
が原因でエラーが発生することに注意してください。
InetAddress.getByAddress("192.168.1.1".toByte)
あなたができる最短は
val ipaddr = Array[Byte](192.toByte, 168.toByte, 1, 9)
あなたする必要があります convert 192
および168
はバイトに変換されます。これは、これらが符号付きバイトの範囲外にあるため有効なバイトリテラルではないためです([-128、127])。
同じことがJavaにも当てはまることに注意してください。以下はコンパイルエラーになります。
byte[] ipaddr = {192, 168, 1, 1};
192および168をバイトにキャストする必要があります。
byte[] ipaddr = {(byte)192, (byte)168, 1, 1};
Array(192, 168, 1, 1).map(_.toByte)
はどうですか?
Chris Martin's answerを展開するには、怠laで、Array(...).map(_.toByte)
を何度も入力したくない場合は、常に変数関数を記述できます。
def toBytes(xs: Int*) = xs.map(_.toByte).toArray
これで、Javaと同じくらい簡潔にバイト配列を宣言できます。
val bytes = toBytes(192, 168, 1, 1) // Array[Byte](-64, -88, 1, 1)
split
String
でトリックを行うことができます:
val ipaddr: Array[Byte] =
"192.168.1.1".split('.').map(_.toInt).map(_.toByte)
これを分解する
"192.168.1.1"
.split('.') // Array[String]("192", "168", "1", "1")
.map(_.toInt) // Array[Int](192, 168, 1, 1)
.map(_.toByte) // Array[Byte](-64, -88, 1, 1)
暗黙的に使用できます
implicit def int2byte(int:Int)= { int.toByte }
そして、それは、バイトが必要な場所でスコープ内のすべてのInt値を変換します。
StringContext
にメソッドを追加することにより、文字列リテラルをバイト配列に変換するためのさまざまなメソッドを簡単に定義できます。たとえば、次のことができます。
_val bytes = ip"192.168.1.15"
_
またはこれ:
_val bytes = hexdump"742d 6761 2e00 6f6e 6574 672e 756e 622e"
_
すべてのバイトの前に「0x」プレフィックスを書き込むと、非常にすぐに迷惑になることがあるため、16進表記のバイト配列を操作するのに特に便利であることに注意してください この例では 。 Array(0xAB, 0xCD, 0xEF).map(_.toByte)
のように16進表記を使用する場合、map
の呼び出しではなく、厄介なのは、すべてのノイズを生成する "0x"プレフィックスの繰り返しです。
以下は、StringContext
をラップする_implicit class
_を提供することにより、バイト配列作成のいくつかの異なる方法を実装する方法を示す小さなコードスニペットです。
_implicit class ByteContext(private val sc: StringContext) {
/** Shortcut to the list of parts passed as separate
* string pieces.
*/
private val parts: List[String] = sc.parts.toList
/** Parses an array of bytes from the input of a `StringContext`.
*
* Applies `preprocess` and `separate` and finally `parseByte`
* to every string part.
* Applies `parseByte` to every vararg and interleaves the
* resulting bytes with the bytes from the string parts.
*
* @param preprocess a string preprocessing step applied to every string part
* @param separate a way to separate a preprocessed string part into substrings for individual bytes
* @param parseByte function used to parse a byte from a string
* @param args varargs passed to the `StringContext`
* @return parsed byte array
*
* Uses a mutable `ListBuffer` internally to accumulate
* the results.
*/
private def parseBytes(
preprocess: String => String,
separate: String => Array[String],
parseByte: String => Byte
)(args: Any*): Array[Byte] = {
import scala.collection.mutable.ListBuffer
val buf = ListBuffer.empty[Byte]
def partToBytes(part: String): Unit = {
val preprocessed = preprocess(part)
if (!preprocessed.isEmpty) {
separate(preprocessed).foreach(s => buf += parseByte(s))
}
}
// parse all arguments, convert them to bytes,
// interleave them with the string-parts
for ((strPart, arg) <- parts.init.Zip(args)) {
partToBytes(strPart)
val argAsByte = arg match {
case i: Int => i.toByte
case s: Short => s.toByte
case l: Long => l.toByte
case b: Byte => b
case c: Char => c.toByte
case str: String => parseByte(str)
case sthElse => throw new IllegalArgumentException(
s"Failed to parse byte array, could not convert argument to byte: '$sthElse'"
)
}
buf += argAsByte
}
// add bytes from the last part
partToBytes(parts.last)
buf.toArray
}
/** Parses comma-separated bytes in hexadecimal format (without 0x-prefix),
* e.g. "7F,80,AB,CD".
*/
def hexBytes(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^,", "").replaceAll(",$", ""), // ,AB,CD, -> AB,CD
_.split(","),
s => Integer.parseInt(s, 16).toByte
)(args: _*)
/** Parses decimal unsigned bytes (0-255) separated by periods,
* e.g. "127.0.0.1".
*/
def ip(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^[.]", "").replaceAll("[.]$", ""), // .1.1. -> 1.1
_.split("[.]"),
s => Integer.parseInt(s, 10).toByte
)(args:_*)
/** Parses byte arrays from hexadecimal representation with possible
* spaces, expects each byte to be represented by exactly two characters,
* e.g.
* "742d 6761 2e00 6f6e 6574 672e 756e 622e".
*/
def hexdump(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll(" ", ""),
_.grouped(2).toArray,
s => Integer.parseInt(s, 16).toByte
)(args: _*)
/** Parses decimal unsigned bytes (0-255) separated by commas,
* e.g. "127.0.0.1".
*/
def decBytes(args: Any*): Array[Byte] = parseBytes(
s => s.replaceAll("^,", "").replaceAll(",$", ""), // ,127, -> 127
_.split(","),
s => Integer.parseInt(s, 10).toByte
)(args:_*)
}
_
このクラスが暗黙のスコープ内にあるとすぐに、次のすべての表記法を使用してバイト配列を定義できます。
_ def printBytes(bytes: Array[Byte]) =
println(bytes.map(b => "%02X".format(b)).mkString("[",",","]"))
// bunch of variables to be inserted in the strings
val a: Int = 192
val b: Long = 168L
val c: Byte = 1.toByte
val d: String = "0F"
val e: String = "15"
printBytes(ip"192.168.1.15")
printBytes(ip"192.$b.1.$e")
printBytes(ip"$a.$b.$c.$e")
printBytes(hexBytes"C0,A8,01,0F")
printBytes(hexBytes"C0,$b,$c,0F")
printBytes(hexBytes"$a,$b,$c,0F")
printBytes(decBytes"192,$b,1,15")
printBytes(decBytes"192,168,$c,$e")
printBytes(decBytes"$a,$b,1,$e")
printBytes(hexdump"C0A8 010F")
printBytes(hexdump"$a $b $c $d")
printBytes(hexdump"C0 $b 01 $d")
_
文字列リテラルには、文字列内で_$varargVar
_構文を使用して変数への参照を含めることもできます。すべての例で同じバイト配列_[C0,A8,01,0F]
_が生成されます。
パフォーマンスについて:上記のすべてはメソッド呼び出しを中心に構築され、リテラルはコンパイル時にバイト配列に変換されません。
特定の例では、代わりにInetAddress.getByName
を使用できます。
InetAddress.getByName("192.168.1.1")
一般に、ディディエは正しいです、Byte
sは-128〜127ですので、これは動作します:
Array[Byte](1,2,3)
しかし、これはしません:
Array[Byte](192, 168, 1, 1)