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--;
}
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.
I am in need to mask PII data for my application. The PII data will be of String format and of variable lengths, as it may include name, address, mail id's etc.
So i need to mask these data before logging them, it should not be a full mask instead, if the length of string is less than or equal to 8 characters then mask the first half with "XXX etc.."
If the length is more than 8 then mask the first and last portion of the string such that only the mid 5 characters are visible.
I know we can do this using java sub-stringa nd iterating over the string, but want to know if there is any other simple solution to address this.
Thanks in advance
If you are using Apache Commons, you can do like
String maskChar = "*";
//number of characters to be masked
String maskString = StringUtils.repeat( maskChar, 4);
//string to be masked
String str = "FirstName";
//this will mask first 4 characters of the string
System.out.println( StringUtils.overlay(str, maskString, 0, 4) );
You can check the string length before generating maskString using if else statement.
You can use this function; change the logic of half's as per your needs:
public static String maskedVariableString(String original)
{
String maskedString = null;
if(original.length()<9)
{
int half = original.length()/2;
StringBuilder sb =new StringBuilder("");
for(int i=0;i<(original.length()-half);i++)
{
sb.append("X");
}
maskedString = original.replaceAll("\\b.*(\\d{"+half+"})", sb.toString()+"$1");
}
else
{
int maskLength = original.length()-5;
int firstMaskLength = maskLength/2;
int secondMaskLength = maskLength-firstMaskLength;
StringBuilder sb =new StringBuilder("");
for(int i=0;i<firstMaskLength;i++)
{
sb.append("X");
}
String firstMask = sb.toString();
StringBuilder sb1 =new StringBuilder("");
for(int i=0;i<secondMaskLength;i++)
{
sb1.append("X");
}
String secondMask = sb1.toString();
maskedString = original.replaceAll("\\b(\\d{"+firstMaskLength+"})(\\d{5})(\\d{"+secondMaskLength+"})", firstMask+"$2"+secondMask);
}
return maskedString;
}
Explanation:
() groups the regular expression and we can use $ to access this group($1, $2,$3).
The \b boundary helps check that we are the start of the digits (there are other ways to do this, but here this will do).
(\d{+half+}) captures (half) no of digits to Group 1. The same happens in the else part also.
I`m working on a project and I had to convert a hex String to a binary String I used a lot of methods but the code below was the most useful to me although this code creates an unknown hex number "l" which looks like 1 but is not one, does some one know what this thing is(l)? and how did it appear and how to fix it and convert it to "1" ?
public String hexToBin(String hex){
String bin =new String();
String binFragment =new String();
int iHex;
hex = hex.trim();
hex = hex.replaceFirst("0x","");
for(int i = 0; i < hex.length(); i++){
iHex = Integer.parseInt(""+hex.charAt(i),16);
binFragment = Integer.toBinaryString(iHex);
while(binFragment.length() < 4){
binFragment = "0" + binFragment;
}
bin += binFragment;
}
You should use Integer.decode() instead of Integer.parseInt() as it handles hex strings as well.
See; http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#decode(java.lang.String)
Use BigInteger.toString(radix). The radix being what base you want to use. So with binary, also known as base2, fill in 2.
static String hexToBin(String s) {
return new BigInteger(s, 16).toString(2);
}
I've an array with hundreds of string values, Is it possible to use specific formats to make them shorter?
e.g
Normal -> "Hello John, What's up?!"
With short format -> "Hello John..."
After using substring, I got errors.
private String[] finalString;
for (int i = 0; i < arrays.PodcastTitle.length; i++) {
finalString[i] = arrays.PodcastTitle[i].substring(0, 5);
}
Since you haven't given any details, this is the shortest approach :
String little = normalString.substring(0, 10); // use anything 5 or 10 or 15, depending on how short you want to make your String
From your edit:
Please change:
private String[] finalString;
to:
private String[] finalString = new String[whateverSizeYouWant];
String toLitteString(String str, int length) {
if (str.length() > length) return str.substring(0, length) + "...";
return str;
}
Function that will truncate longer strings to length (and add a "...") or return the short string. If you want the length to include the "..." then just change length to length - 3.
Why won't you consider implementing a method that takes a String argument, explodes it by space character and returns the String with required number of words in it?
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);