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();
}
Related
Edited
I am trying to implement the following functions in my program using hashmap.
get
getBit
set
setBit
Here is the code.
static HashMap<String, Object> hashmap = new HashMap<String, Object>();
public static String dictGet(String key){
String val = (String) hashmap.get(key);
return val;
}
public static int dictGet(String key, int pos){
String val = (String) hashmap.get(key);
byte[] bytes = val.getBytes();
byte byt = bytes[pos /8];
System.out.println("Byte : "+byt);
return (byt >> (pos % 8) ) & 1;
}
public static void dictSet(String key, String val){
hashmap.put(key, val);
}
public static void dictSet(String key, int pos, byte bitval){
String val = (String) hashmap.get(key);
byte[] bytes = val.getBytes();
byte byt = bytes[pos /8];
if(bitval == 1){
bytes[pos /8] = (byte) (bytes[pos /8]| (1 << (pos % 8)));
}
else if(bitval == 0){
bytes[pos /8] = (byte) (bytes[pos /8] & ~(1 << (pos % 8)));
}
hashmap.put(key, new String(bytes));
}
I want to achieve O(1) complexity for each of these functions. But currently getBit() and setBit() functions are taking O(n) time complexity.
Any help is appreciated.
This is very inefficient. val.getBytes() will allocate new array (actually more than one) and encode whole string into it every time you call it. This is likely going to be the most expensive operation in this snippet.
Moreover, this code mixes two completely different representations. To make your intentions clear and avoid mistakes, you should stick to one. If you want to operate on bytes, store byte[] in your hash map. If you want to operate on characters or code points use charAt or codePointAt. If you need to convert between those representation, do it once during initialization.
Notice also, that getBytes encodes the string using platform's default charset. This, most likely, is not what you want and your code will break, if UTF-16 is used.
Here is an example using StringBuilder, Note that in Java char has 16 bits and this code uses that full range:
package test;
import java.util.HashMap;
import java.util.Map;
public class Test {
Map<String, StringBuilder> map = new HashMap<>();
void setBit(final String key, final int n) {
final StringBuilder s = this.map.get(key);
final char c = s.charAt(n / 16);
s.setCharAt(n / 16, (char) (c | 1 << n % 16));
}
int getBit(final String key, final int n) {
final StringBuilder s = this.map.get(key);
final int c = s.charAt(n / 16);
return (c << n % 16 & 0x8000) != 0 ? 1 : 0;
}
CharSequence getValue(final String key) {
return this.map.get(key);
}
public static void main(final String[] args) {
final Test t = new Test();
t.map.put("x", new StringBuilder("abc"));
t.map.put("y", new StringBuilder("abc"));
t.setBit("x", 3);
t.setBit("y", 4);
// many methods accept any CharSequence not just String
final CharSequence xValue = t.getValue("x");
final CharSequence yValue = t.getValue("y");
System.out.println(String.join(",", xValue, yValue));
}
}
No, the complexity of this is not O(1), it is O(n), where n is the length of the string. The reason for this is that bytes that you receive from getBytes() must always be a copy; otherwise, String's immutability would be compromised.
This can be confirmed by looking at the source code: getBytes calls encode, which calls Arrays.copyOf:
static byte[] encode(Charset cs, char[] ca, int off, int len) {
StringEncoder se = new StringEncoder(cs, cs.name());
char[] c = Arrays.copyOf(ca, ca.length); // <<=== Copying an array is O(n)
return se.encode(c, off, len);
}
To get O(1) amortized complexity (assuming that you are going to access most bits of a string) you would need additional storage - a HashMap<String,byte[]> which would be a "parallel map" to the original hash map, storing "cached" values of getBytes() calls. Start by looking for a cached representation; if it is not there, go for the actual value, call getBytes(), and cache the result. The rest of the code would remain the same.
byte[] bytes = cache.get(key);
if (bytes == null) {
String val = (String) hashmap.get(key);
bytes = val.getBytes();
cache.put(key, bytes);
}
byte byt = bytes[pos /8];
System.out.println("Byte : "+byt);
return (byt >> (pos % 8) ) & 1;
Note that the maintenance of cache is on you: each time that you modify hashmap you need to remove the corresponding key from the cache.
I know this not related to your answer, but if you are using Java, you should be using generic types so that the cast is not required.
Coming to your answer, the complexity of String.getBytes() depends on the length of the String. Think in this way, the getBytes() method convert every character in the String to a byte. Hence, the complexity is O(L), where L is the length of the String.
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.
I have sort of a funky question (that I hope hasn't been asked and answered yet). To start, I'll tell you the order of what I'm trying to do and how I'm doing it and then tell you where I'm having a problem:
Convert a string of characters into ASCII numbers
Convert those ASCII numbers into binary and store them in a string
Convert those binary numbers back into ASCII numbers
Convert the ASCII numbers back into normal characters
Here are the methods I've written so far:
public static String strToBinary(String inputString){
int[] ASCIIHolder = new int[inputString.length()];
//Storing ASCII representation of characters in array of ints
for(int index = 0; index < inputString.length(); index++){
ASCIIHolder[index] = (int)inputString.charAt(index);
}
StringBuffer binaryStringBuffer = new StringBuffer();
/* Now appending values of ASCIIHolder to binaryStringBuffer using
* Integer.toBinaryString in a for loop. Should not get an out of bounds
* exception because more than 1 element will be added to StringBuffer
* each iteration.
*/
for(int index =0;index <inputString.length();index ++){
binaryStringBuffer.append(Integer.toBinaryString
(ASCIIHolder[index]));
}
String binaryToBeReturned = binaryStringBuffer.toString();
binaryToBeReturned.replace(" ", "");
return binaryToBeReturned;
}
public static String binaryToString(String binaryString){
int charCode = Integer.parseInt(binaryString, 2);
String returnString = new Character((char)charCode).toString();
return returnString;
}
I'm getting a NumberFormatException when I run the code and I think it's because the program is trying to convert the binary digits as one entire binary number rather than as separate letters. Based on what you see here, is there a better way to do this overall and/or how can I tell the computer to recognize the ASCII characters when it's iterating through the binary code? Hope that's clear and if not I'll be checking for comments.
So I used OP's code with some modifications and it works really well for me.
I'll post it here for future people. I don't think OP needs it anymore because he probably figured it out in the past 2 years.
public class Convert
{
public String strToBinary(String inputString){
int[] ASCIIHolder = new int[inputString.length()];
//Storing ASCII representation of characters in array of ints
for(int index = 0; index < inputString.length(); index++){
ASCIIHolder[index] = (int)inputString.charAt(index);
}
StringBuffer binaryStringBuffer = new StringBuffer();
/* Now appending values of ASCIIHolder to binaryStringBuffer using
* Integer.toBinaryString in a for loop. Should not get an out of bounds
* exception because more than 1 element will be added to StringBuffer
* each iteration.
*/
for(int index =0;index <inputString.length();index ++){
binaryStringBuffer.append(Integer.toBinaryString
(ASCIIHolder[index]));
}
String binaryToBeReturned = binaryStringBuffer.toString();
binaryToBeReturned.replace(" ", "");
return binaryToBeReturned;
}
public String binaryToString(String binaryString){
String returnString = "";
int charCode;
for(int i = 0; i < binaryString.length(); i+=7)
{
charCode = Integer.parseInt(binaryString.substring(i, i+7), 2);
String returnChar = new Character((char)charCode).toString();
returnString += returnChar;
}
return returnString;
}
}
I'd like to thank OP for writing most of it out for me. Fixing errors is much easier than writing new code.
You've got at least two problems here:
You're just concatenating the binary strings, with no separators. So if you had "1100" and then "0011" you'd get "11000011" which is the same result as if you had "1" followed by "1000011".
You're calling String.replace and ignoring the return result. This sort of doesn't matter as you're replacing spaces, and there won't be any spaces anyway... but there should be!
Of course you don't have to use separators - but if you don't, you need to make sure that you include all 16 bits of each UTF-16 code point. (Or validate that your string only uses a limited range of characters and go down to an appropriate number of bits, e.g. 8 bits for ISO-8859-1 or 7 bits for ASCII.)
(I have to wonder what the point of all of this is. Homework? I can't see this being useful in real life.)
I need to verify that a code generated in one class is same as code verified in another class. But the twist is in other class the logic used is different. Its like this.
Class A:
String = "0A2D" (suppose)
i used the substring method, take out 0A , 2D and convert them into Decimal values & store them as bytes.
the end result will look something like this
int a1 = (byte) Integer.parseInt(s,16); here s= 0A
int a2 = (byte) Integer.parseInt(s,16); here s= 2D
so a1 would be 10 ( 1byte memory) , a2 would be 45 (1byte memory)
Class B:
In this class i'm supposed to use the method getBytes(). But when i use that I see some strange o/p saying [B#...... Firstly I need information about what is happening there actually. How is it getting encoded. Secondly the o/p here should be an array of bytes matching with o/p of Class A. i.e
byte[] b = {a1a2} ( memory 2bytes)
b = {1045}
So at the end A would be having 2 values with 1byte each. But B would have an array which would have the same two values but the memory size would be 2bytes.
I hope I'm clear in my ques & didnt confuse.
your kind help would be appreciated. thanks in advance.
What line of code gives the output "[B#......"? (I assume the dots mean you truncated the output.) This particular output appears as if you are trying to print the array reference rather than the elements of the array. You should either use a for loop to print the individual elements or use Array.toString() to get a String representation of the array.
Your language is slightly unclear but I think the following will do what you want:
byte[] b = new byte[] { a1, a2 };
Array initializers are a very useful feature of the language.
probably you are just printing it wrong when printing arrays use Arrays.toString(arr)
I assume when you say byte[] b = {a1a2} you mean byte[] b = {a1,a2}
If you want to print out the contents of a byte[] you need to convert it into a String first.
Here's a useful method to convert a byte array into a readable string:
public static String toHexString(byte[] data)
{
if (data == null) return "";
char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[data.length * 2];
int v;
for ( int j = 0; j < data.length; j++)
{
v = data[j] & 0xFF;
hexChars[j*2] = hexArray[v/16];
hexChars[j*2 + 1] = hexArray[v%16];
}
return new String(hexChars);
}
From there you should be able to work out the rest.
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);