I have a KTable in Kafka that when I debug I get the data in bytes.
If I want it in String, what should I do? I have attached an snippet as well.
The key of the LinkedHashMap is a string. If you expand any String in the debugger, you'll see its byte representation.
That highlighted "value" is not the value of the map's keys, that would be the value field in the bottom of the screenshot.
Plus, you're expanding the topology builder, which is not the actual values in the Table. If you want to see the data in the table, table.toStream().print()
Something like:
public static String byteArrayToHexString(byte[] rawBytes) {
final String HEXCHARS = "0123456789abcdef";
StringBuilder sb = new StringBuilder(rawBytes.length * 2);
for (int i = 0; i < rawBytes.length; i++) {
int ix = (rawBytes[i] >> 4) & 0xF;
sb.append(HEXCHARS.charAt(ix));
ix = rawBytes[i] & 0xF;
sb.append(HEXCHARS.charAt(ix));
}
return sb.toString();
}
I am looking for a way to read hex strings from a file line by line and append them as converted bytes to some ByteBuffer.
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
Files.lines(filePath).foreach( l ->
byteBuffer.put(
// first of all strip newlines and normalize string
l.replaceAll("/\n|\r/g", "").toUpperCase()
// but what to do here?
// is there something like
// take next 2 characters (-> Consumer)
// and replace them with the converted byte?
// E.g. "C8" -> 0xC8
// until the end of the string is reached
)
);
This has been answered a million time. But I wondered if there is a solution using streams like returned by Files.lines().
Generally I like this answer. Can anybody help me about translating that into java-8 stream-based solution or completing my example from above?
Thank you!
You can use a utility method to parse the line as a hex string to a byte array:
public static byte[] hexStringToByteArray(String str) {
if(str.startsWith("0x")) { // Get rid of potential prefix
str = str.substring(2);
}
if(str.length() % 2 != 0) { // If string is not of even length
str = '0' + str; // Assume leading zeroes were left out
}
byte[] result = new byte[str.length() / 2];
for(int i = 0; i < str.length(); i += 2) {
String nextByte = str.charAt(i) + "" + str.charAt(i + 1);
// To avoid overflow, parse as int and truncate:
result[i / 2] = (byte) Integer.parseInt(nextByte, 16);
}
return result;
}
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
Files.lines(filePath).forEach( l ->
byteBuffer.put(
hexStringToByteArray(l.replaceAll("/\n|\r/g", "").toUpperCase())
)
);
This looks a bit like an xy problem, as reading the file “line by line” is already part of your attempted solution while you actual task does not include any requirement to read the file “line by line”.
Actually, you want to process all hexadecimal numbers of the source, regardless of the line terminators, which is a job for java.util.Scanner. It also allows to process the items using the Stream API, though this specific task does not benefit much from it, compared to a loop:
ByteBuffer bb = ByteBuffer.allocate(1024);
try(Scanner s = new Scanner(yourFile)) {
s.findAll("[0-9A-Fa-f]{2}")
.mapToInt(m -> Integer.parseInt(m.group(), 16))
.forEachOrdered(i -> { if(bb.hasRemaining()) bb.put((byte)i); });
}
try(Scanner s = new Scanner(yourFile)) {
Pattern p = Pattern.compile("[0-9A-Fa-f]{2}");
for(;;) {
String next = s.findWithinHorizon(p, 0);
if(next == null) break;
if(!bb.hasRemaining()) // the thing hard to do with Stream API
bb = ByteBuffer.allocate(bb.capacity()*2).put(bb.flip());
bb.put((byte)Integer.parseInt(next, 16));
}
}
Note that these examples use Java 9. In Java 8, the Buffer returned by Buffer.flip() needs a type cast back to ByteBuffer and Scanner.findAll is not available but has to be replaced by a back-port like the one in this answer.
Considering the following String
String hexData = "1E01";
Is there a simple implementation to turn any hexData into a bit-based String array, like
String hexDataBits = "0001111000000001";
?
Here you go. Convert your hex string to an int value using the built in parseInt function, then turn that into a binary string.
public String hexToBinary(String hexBits) {
int intversion = Integer.parseInt(hexBits, 16);
String binaryVers = Integer.toBinaryString(intversion);
return binaryVers;
}
Note that this is not padded. If you want to pad it, modify binaryVers.
eg:
// if you're dead set on having at least 16 chars, put this before the return statement
int padding = 16 - binaryVers.length();
while (padding > 0) {
binaryVers = "0" + binaryVers;
padding--;
}
How can I convert the specific code written in Delphi to JAVA?
Delphi code is encrypt code.
function Encrypt(const S: String; Key1, Key2, Key3: WORD): String;
var
i: Byte;
FirstResult: String;
begin
SetLength(FirstResult, Length(S));
for i:=1 to Length(S) do begin
FirstResult[i]:=Char(Byte(S[i]) xor (Key1 shr 8));
Key1 :=(Byte(FirstResult[i])+Key1)*Key2+Key3;
end;
Result:=ValueToHex(FirstResult);
end;
function ValueToHex(const S: String): String;
var i: Integer;
begin
SetLength(Result, Length(S)*2);
for i:=0 to Length(S)-1 do begin
Result[(i*2)+1]:=HexaChar[Integer(S[i+1]) shr 4];
Result[(i*2)+2]:=HexaChar[Integer(S[i+1]) and $0f];
end;
end;
so I was try to make source code. it's here
int key1=11; int key2=22; int key3=33;
String value = "ABCDE";
for(int i=0; i< value.length(); i++){
byte[] bValue = value.substring(i).getBytes();
int[] rValue = {0};
rValue[0] = bValue[0]^(key1>>8);
key1 = (bValue[0]+key1)*key2+key3;
System.out.print(ValueToHex(rValue));
}
But different results.
key1 = 11, key2 = 22, key3 = 33;
value : "ABCDE"
delphi encrypt : 4144DB69BF
java encrypt : 4144DB0901
Does not match
but
value : "ABC"
delphi encrypt : 4144DB
java encrypt : 4144DB
Is consistent
Why does not match the long?
There are two distinct errors.
Firstly, the updating of key1 must use rValue rather than bValue.
And secondly, the Delphi code performs arithmetic on key1 in the context of Word which is a 2 byte unsigned integer. But the Java code performs the same calculations in the context of int which is a 4 byte signed integer.
To fix this I believe you simply need to perform the arithmetic using 4 byte signed and then truncate key1 to a 2 byte value. Like this:
key1 = ((rValue[0]+key1)*key2+key3) & 0xffff;
I also think that you can simplify the Java code considerably. I know next to nothing about Java and so I'm sure a skilled Java expert could do very much better than this:
class SO15885898 {
private static String ValueToHex(int myInt)
{
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(myInt & 0xff));
if (sb.length() < 2) {
sb.insert(0, '0'); // pad with leading zero if needed
}
return sb.toString();
}
public static void main(String[] args)
{
int key1=11;
int key2=22;
int key3=33;
String value = "ABCDE";
for(int i=0; i<value.length(); i++){
byte bValue = value.substring(i).getBytes()[0];
int rValue = bValue^(key1>>8);
key1 = ((rValue+key1)*key2+key3) & 0xffff;
System.out.print(ValueToHex(rValue));
}
}
}
Output:
4144db69bf
On a more general note, since you have both codes, you should arrange that both codes are as close to each other in organisation as possible. And then print off as much diagnostics as possible to pinpoint the calculation step where differences first appear.
This question already has answers here:
Simple way to repeat a string
(32 answers)
Closed 4 years ago.
I did check the other questions; this question has its focus on solving this particular question the most efficient way.
Sometimes you want to create a new string with a specified length, and with a default character filling the entire string.
ie, it would be cool if you could do new String(10, '*') and create a new String from there, with a length of 10 characters all having a *.
Because such a constructor does not exist, and you cannot extend from String, you have either to create a wrapper class or a method to do this for you.
At this moment I am using this:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
char[] array = new char[length];
int pos = 0;
while (pos < length) {
array[pos] = charToFill;
pos++;
}
return new String(array);
}
It still lacks any checking (ie, when length is 0 it will not work). I am constructing the array first because I believe it is faster than using string concatination or using a StringBuffer to do so.
Anyone else has a better sollution?
Apache Commons Lang (probably useful enough to be on the classpath of any non-trivial project) has StringUtils.repeat():
String filled = StringUtils.repeat("*", 10);
Easy!
Simply use the StringUtils class from apache commons lang project. You have a leftPad method:
StringUtils.leftPad("foobar", 10, '*'); // Returns "****foobar"
No need to do the loop, and using just standard Java library classes:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
if (length > 0) {
char[] array = new char[length];
Arrays.fill(array, charToFill);
return new String(array);
}
return "";
}
As you can see, I also added suitable code for the length == 0 case.
Some possible solutions.
This creates a String with length-times '0' filled and replaces then the '0' with the charToFill (old school).
String s = String.format("%0" + length + "d", 0).replace('0', charToFill);
This creates a List containing length-times Strings with charToFill and then joining the List into a String.
String s = String.join("", Collections.nCopies(length, String.valueOf(charToFill)));
This creates a unlimited java8 Stream with Strings with charToFill, limits the output to length and collects the results with a String joiner (new school).
String s = Stream.generate(() -> String.valueOf(charToFill)).limit(length).collect(Collectors.joining());
In Java 11, you have repeat:
String s = " ";
s = s.repeat(1);
(Although at the time of writing still subject to change)
char[] chars = new char[10];
Arrays.fill(chars, '*');
String text = new String(chars);
To improve performance you could have a single predefined sting if you know the max length like:
String template = "####################################";
And then simply perform a substring once you know the length.
Solution using Google Guava
String filled = Strings.repeat("*", 10);
public static String fillString(int count,char c) {
StringBuilder sb = new StringBuilder( count );
for( int i=0; i<count; i++ ) {
sb.append( c );
}
return sb.toString();
}
What is wrong?
using Dollar is simple:
String filled = $("=").repeat(10).toString(); // produces "=========="
Solution using Google Guava, since I prefer it to Apache Commons-Lang:
/**
* Returns a String with exactly the given length composed entirely of
* the given character.
* #param length the length of the returned string
* #param c the character to fill the String with
*/
public static String stringOfLength(final int length, final char c)
{
return Strings.padEnd("", length, c);
}
The above is fine. Do you mind if I ask you a question - Is this causing you a problem? It seams to me you are optimizing before you know if you need to.
Now for my over engineered solution. In many (thou not all) cases you can use CharSequence instead of a String.
public class OneCharSequence implements CharSequence {
private final char value;
private final int length;
public OneCharSequence(final char value, final int length) {
this.value = value;
this.length = length;
}
public char charAt(int index) {
if(index < length) return value;
throw new IndexOutOfBoundsException();
}
public int length() {
return length;
}
public CharSequence subSequence(int start, int end) {
return new OneCharSequence(value, (end-start));
}
public String toString() {
char[] array = new char[length];
Arrays.fill(array, value);
return new String(array);
}
}
One extra note: it seems that all public ways of creating a new String instance involves necessarily the copy of whatever buffer you are working with, be it a char[], a StringBuffer or a StringBuilder. From the String javadoc (and is repeated in the respective toString methods from the other classes):
The contents of the character array are copied; subsequent modification of
the character array does not affect
the newly created string.
So you'll end up having a possibly big memory copy operation after the "fast filling" of the array. The only solution that may avoid this issue is the one from #mlk, if you can manage working directly with the proposed CharSequence implementation (what may be the case).
PS: I would post this as a comment but I don't have enough reputation to do that yet.
Try this Using the substring(int start, int end); method
String myLongString = "abcdefghij";
if (myLongString .length() >= 10)
String shortStr = myLongString.substring(0, 5)+ "...";
this will return abcde.
Mi solution :
pw = "1321";
if (pw.length() < 16){
for(int x = pw.length() ; x < 16 ; x++){
pw += "*";
}
}
The output :
1321************
Try this jobber
String stringy =null;
byte[] buffer = new byte[100000];
for (int i = 0; i < buffer.length; i++) {
buffer[i] =0;
}
stringy =StringUtils.toAsciiString(buffer);