There are lots of components out there creating/parsing barcode images but i could not manage to find a library which parses a EAN-128 barcode-string and gives me simply a java-pojo object from which I can get EAN-128 groups if they were included in the barcode.
Example pseudocode:
EAN128Pojo pojo = EAN128Pojo.parse(some string got from scanner);
Date dueDate = pojo.getDueDate();
or
Object dueDate = pojo.get("12" /*application identifier for due date*/);
Is there any library capable of this?
I don't know of any, and neither does Google CodeSearch: http://www.google.com/codesearch?q=getAdditionalProductIdentification
Anyway, writing your own isn't that difficult. This one took me less than an hour:
package so5685964;
import java.util.Map;
import org.joda.time.DateMidnight;
import com.google.common.collect.Maps;
public class GS1Code128Data {
/** Maps the AI to the corresponding data from the barcode. */
private final Map<String, String> data = Maps.newHashMap();
private static final Map<String, AII> aiinfo = Maps.newHashMap();
static class AII {
final int minLength;
final int maxLength;
public AII(String id, int minLength, int maxLength) {
this.minLength = minLength;
this.maxLength = maxLength;
}
}
private static void ai(String id, int minLength, int maxLength) {
aiinfo.put(id, new AII(id, minLength, maxLength));
}
private static void ai(String id, int length) {
aiinfo.put(id, new AII(id, length, length));
}
static {
ai("00", 18, 18);
ai("01", 14);
ai("02", 14);
ai("10", 1, 20);
ai("11", 6);
ai("12", 6);
// TODO: continue according to http://en.wikipedia.org/wiki/GS1-128
}
/**
* Decodes a Unicode string from a Code128-like encoding.
*
* #param fnc1 The character that represents FNC1.
*/
public GS1Code128Data(String s, char fnc1) {
StringBuilder ai = new StringBuilder();
int index = 0;
while (index < s.length()) {
ai.append(s.charAt(index++));
AII info = aiinfo.get(ai.toString());
if (info != null) {
StringBuilder value = new StringBuilder();
for (int i = 0; i < info.maxLength && index < s.length(); i++) {
char c = s.charAt(index++);
if (c == fnc1) {
break;
}
value.append(c);
}
if (value.length() < info.minLength) {
throw new IllegalArgumentException("Short field for AI \"" + ai + "\": \"" + value + "\".");
}
data.put(ai.toString(), value.toString());
ai.setLength(0);
}
}
if (ai.length() > 0) {
throw new IllegalArgumentException("Unknown AI \"" + ai + "\".");
}
}
private static DateMidnight asDate(String s) {
if (s == null) {
return null;
}
String century = s.compareTo("500000") < 0 ? "20" : "19";
return new DateMidnight(century + s);
}
public DateMidnight getDueDate() {
return asDate(data.get("12"));
}
}
And some demonstration code:
package so5685964;
public class BarcodeDemo {
public static void main(String[] args) {
String barcode = "12110416";
GS1Code128Data data = new GS1Code128Data(barcode, '\f');
System.out.println(data.getDueDate());
}
}
When you assume that your input is already a String, pay attention to encoding issues. The FNC1 code does not have a corresponding Unicode Code Point, so it has to be encoded in some other way.
The GS1 Barcode Syntax Engine is a native library with a Java binding that is purpose built for processing GS1 Application Identifier syntax.
https://github.com/gs1/gs1-syntax-engine
Related
I do not know the site, and I have only asked one question here. I have no idea - how to handle a code problem. I tried a lot - but I could not fix.
I use StringBuilder - for because of its benefits according to the standard string
I want to delete the first character in the string - but the character that appears in the last place - is duplicated - in the last two places.
for example:
i have the String abcdef, when i delete - the first instace - 'a':
i got back the String bcdeff
well i try - to set the length of the String to original length minus one - but this dont give any result.
i try also - to set the string to new String - and after that - send the String that i was save in tmp string - but this do help either.
public void appendBuffer(StringBuilder dictionary)
{
for (int i = 0; i < appendToWindowBuffer; i++) {
if(dictionary.length() == windowSize)
{
dictionary.deleteCharAt(0);
}
if(nextByteIndex<source.length )
{
dictionary.append((char)source[nextByteIndex]);
nextByteIndex++;
}
else
{
currentLookaheadBufferSize--;
}
if(currentSearchBufferSize < searchBufferSize)
{
currentSearchBufferSize++;
}
}
appendToWindowBuffer = 0;
}
full code:
main class
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException
{
System.out.println("main");
String inPath = "C:\\Users\\avraam\\Documents\\final-assignment\\LZ77\\source.txt";
String outPath = "C:\\Users\\avraam\\Documents\\final-assignment\\LZ77\\encoded.txt";
String decompressedPath = "C:\\Users\\avraam\\Documents\\final-assignment\\LZ77\\decoded.txt";
int windowSize = 14;
int lookaheadBufferSize = 6;
LZ77 compress = new LZ77(inPath,outPath,windowSize,lookaheadBufferSize);
compress.compress();
}
}
match class
public class Match {
protected int length;
protected int offset;
protected String value;
public Match(int length, int offset, String value)
{
this.length=length;
this.offset=offset;
this.value = value;
}
public void SetOffset(int offset) { this.offset = offset; }
public void SetLength(int length) { this.length = length; }
public void SetValue(String value) { this.value = value; }
public void AddValue(char value) { this.value += value; }
public void Reset()
{
this.offset = 0;
this.length = 0;
this.value = "";
}
}
LZ77 class
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
public class LZ77 {
private String inPath = null;
private String outPath = null;
private File inFile;
private File outFile;
private final int windowSize;
private final int lookaheadBufferSize;
private final int searchBufferSize;
private int nextByteIndex = 0;
//private int lookAheadIndex = 0; //not always should be (windowsize - lookaheadBufferSize.) in the end maybr will be less character in the lookAhead buffer. the index when LookAhead start is equel to the length of SearchBuffer
private int currentSearchBufferSize = 0;
private int currentLookaheadBufferSize = 0;
private int appendToWindowBuffer = 0;
private byte[] source = null;
public LZ77(String inPath,String outPath,int windowSize,int lookaheadBufferSize) throws IOException
{
this.inPath = inPath;
this.outPath = outPath;
this.inFile = new File(inPath);
this.outFile = new File(outPath);
this.windowSize = windowSize;
this.lookaheadBufferSize = lookaheadBufferSize;
this.searchBufferSize = windowSize - lookaheadBufferSize;
this.source = Files.readAllBytes(inFile.toPath());
}
public void compress() throws IOException
{
/*
* 1. create whole windowBuffer (named - `dictionary`)- that will by used by lookahead and by search Buffers.
* 2. create compressed data - where the data that compressed will be send.
* 3. initialize dictionary - look a head buffer by giving it the size of `lookaheadBuffer`.
* 4. start encode.
* 5. make the encode.
*/
System.out.println("compress");
System.out.println("read the file.");
System.out.println("check if source array work: ");
for (int element: source) {
System.out.print((char)element + "");
}
System.out.println("call to bufferInitialize function");
StringBuilder dictionary = new StringBuilder();
bufferInitialize(dictionary);
System.out.println(dictionary.toString());
StringBuilder compressed = new StringBuilder();
encode(dictionary,compressed);
}
public void bufferInitialize(StringBuilder dictionary)
{
System.out.println("bufferInitialize");
for (int i = 0; i < lookaheadBufferSize; i++) {
dictionary.append((char)source[nextByteIndex]);
nextByteIndex++;
currentLookaheadBufferSize++;
}
// initialize the buffer in the beginning with look a head buffer.
}
public void bufferUpdate()
{
// gets int length - and read those number of bytes - from `inPath` source file.
}
public void encode(StringBuilder dictionary,StringBuilder compressed)
{
//while(nextByteIndex < source.length)
while(currentLookaheadBufferSize > 0)
{
Match match = findMatch(dictionary);
System.out.print("<"+match.offset + ","+match.length+","+ dictionary.charAt(currentSearchBufferSize + match.length) + ">");
appendToWindowBuffer = increaseBuffer(match.length);
appendBuffer(dictionary);
}
/**
* do while you reach to the end of the file
* check if there any possible match
* if do so
* find the maxMatch try always to add another character DONE
* call update function -
* the function will update the
* windowbuffer(dictionary), DONE
* nextByteIndex and DONE
* the position of the index that begins the lookAheadBuffer
* and size of the lookahead and
* search buffers, and
* reset the appendToWindowBuffer. DONE
*/
}
public void convertStringToBits()
{
}
public Match findMatch(StringBuilder dictionary)
{
/**
* function get the window buffer - and index to start.
* the function will be find the max match that starts from index 0 to index start (we cant start search after the `start index`)
* because this parts belong to the look a head buffer.
* #param
* #return
*/
Match match= new Match(0,0, "");
String matchedString = null;
int offset;
int matchLookAheadIndex = currentSearchBufferSize;
if(!haveAnyMatch(dictionary))
{
addMatch();
}
else {
matchedString = "" + dictionary.charAt(matchLookAheadIndex);
offset = findMatchIndex(dictionary,matchedString);
while(offset != -1)
{
match.SetLength(match.length + 1);
match.SetOffset(offset);
match.SetValue(matchedString);
matchLookAheadIndex++;
matchedString +=dictionary.charAt(matchLookAheadIndex);
offset = findMatchIndex(dictionary,matchedString);
}
}
return match;
}
public int findMatchIndex(StringBuilder dictionary,String value)
{
int stringLength = value.length();
String tmpMatch = null;
int offsetMatch;
for (int i = currentSearchBufferSize - 1; i >=0; i--)
{
tmpMatch = dictionary.substring(i, i +stringLength );
offsetMatch = currentSearchBufferSize - i;
if(tmpMatch.equals(value))
{
System.out.println("data was match is searchWindow");
System.out.println("the offset from LookAHead is: " + offsetMatch);
return offsetMatch;
}
}
return -1;
}
public boolean haveAnyMatch(StringBuilder dictionary)
{
if (currentSearchBufferSize == 0)
{
System.out.println("dont have match - search buffer is empty now");
return false;
}
if(!isExistInSearchBuffer(dictionary,dictionary.charAt(currentSearchBufferSize)))
{
System.out.println("dont have match - the first character in lookAheadBuffer wasn't found in searchBuffer");
return false;
}
return true;
/*
* check:
* if search buffer is empty
* if the needed character isn't exist in the search buffer
* if the current value is big enough - and match was not found.
*/
}
public boolean isExistInSearchBuffer(StringBuilder dictionary, char isCharAtDictionary)
{
for (int i = 0; i < currentSearchBufferSize; i++) {
if(dictionary.charAt(i) == isCharAtDictionary)
{
return true;
}
}
return false;
}
public void nextMatch(StringBuilder dictionary)
{
/**
* #param: value, window buffer.
* #description: find the current match with the needed value in the search buffer boundaries.
*/
}
public int increaseBuffer(int matchLength)
{
return 1 + matchLength;
/*
* return int - that calulate by how many byte we need to increase the buffer
*/
}
public void addMatch()
{
}
public void addBitSize() {
}
public void appendBuffer(StringBuilder dictionary)
{
for (int i = 0; i < appendToWindowBuffer; i++) {
if(dictionary.length() == windowSize)
{
dictionary.deleteCharAt(0);
}
if(nextByteIndex<source.length )
{
dictionary.append((char)source[nextByteIndex]);
nextByteIndex++;
}
else
{
currentLookaheadBufferSize--;
}
if(currentSearchBufferSize < searchBufferSize)
{
currentSearchBufferSize++;
}
}
appendToWindowBuffer = 0;
}
}
This seems to work:
StringBuilder builder = new StringBuilder("abcdef");
builder.deleteCharAt(0);
System.out.println(builder.toString());
Prints: bcdef
How are you doing it?
the solution that work for me:
i need to write the decompress - to outout file.
I registered to the file - in CHAR - this is not true - need to register output in BYTE
WORNG WAY THAT I DO:
private void writeDecode (StringBuilder decompress) throws IOException
{
Writer write = new FileWriter(this.outFile);
write.write(decompress.toString());
write.close();
}
THE CORRECT WAY
private void WriteToFile(StringBuilder decodedData) throws IOException
{
FileOutputStream outputFileStream = new FileOutputStream(this.outPath);
for(int i = 0; i < decodedData.length(); i++)
{
byte currentByte = (byte)decodedData.charAt(i);
outputFileStream.write(currentByte);
}
outputFileStream.close();
}
I need to register in the file in BYTE - this is the right way.
I have a string that might contain both Unicode and UTF-8 characters. This makes it difficult when I want to save them to a database that doesn't deal with Unicode characters. The database I am using is PostgreSQL. They might be to big for a certain column this is a simple example for my situation
public static void main(String[] args) {
String test= "İİİİİİİİİİ";
byte[] bytesOrig = null;
bytesOrig = test.getBytes("UTF-8");
System.out.println("bytesOrig="+new String(bytesOrig));
byte[] bytesFive = new byte[5];
System.arraycopy(bytesOrig, 0, bytesFive, 0, 5);
System.out.println("bytes-Five="+new String(bytesFive));
System.out.println("Substring="+test.substring(0,5));
System.out.println("Substring real length=" + test.substring(0,5).getBytes().length);
}
I cant use the String.substring method since it will NOT help me in case of double bytes characters - i have tried working with Bytes-Array copy but it means that the last characters might be deleted.
And this is the Debug info:
bytesOrig=İİİİİİİİİİ
bytes-Five=İİ�
Substring=İİİİİ
Substring real length=10
You can see since I have only part of the Bytes array - I don't want the last character to appear as �
You can try this: the changing places are shows in comment.
public static void main(String[] args) throws UnsupportedEncodingException {
String test= "İİİİİİİİİİ";
System.out.println("test.length() = " + test.length()); // out: 10
byte[] bytesOrig;
bytesOrig = test.getBytes("UTF-8"); // but after get bytes will return 20
System.out.println("bytesOrig.length = " + bytesOrig.length); // it
System.out.println("bytesOrig="+new String(bytesOrig));
byte[] bytesFive = new byte[10]; // 1. so change here to twice
System.arraycopy(bytesOrig, 0, bytesFive, 0, 10); // 2. change here also
System.out.println("bytes-Five="+new String(bytesFive));
System.out.println("Substring="+test.substring(0,5));
System.out.println("Substring real length=" + test.substring(0,5).getBytes().length);
}
And here is the output:
test.length() = 10
bytesOrig.length = 20
bytesOrig=İİİİİİİİİİ
bytes-Five=İİİİİ
Substring=İİİİİ
Substring real length=10
Most of the logic is done at transformOverhead method
according to the value, we will increase i.
public class ZoneTrimTransformer implements ZoneTransformer {
private int maxLength;
public ZoneTrimTransformer(int maxLength) {
this.maxLength = maxLength;
}
#Override
public Object transform(Object value) {
if (value == null) {
return null;
}
else {
String val = value.toString();
if (getDBRequireLength(val) > getJavaLength(val) ){
return transformOverhead(val);
}
else if (val != null && getJavaLength(val) > maxLength) {
// Trim
val = val.substring(0, maxLength);
}
return val;
}
}
public static void main(String[] args) {
System.out.println("1234567".substring(0, 5));
}
public int getJavaLength(String val) {
return val.length();
}
public int getDBRequireLength(String val) {
return val.getBytes().length;
}
private Object transformOverhead(Object s) {
byte[] byeArray = s.toString().getBytes();
if (byeArray.length < maxLength) maxLength = byeArray.length;
int n16 = 0;
int advance = 1;
int i = 0;
while (i < maxLength) {
advance = 1;
if ((byeArray[i] & 0x80) == 0) i += 1;
else if ((byeArray[i] & 0xE0) == 0xC0) i += 2;
else if ((byeArray[i] & 0xF0) == 0xE0) i += 3;
else { i += 4; advance = 2; }
if (i <= maxLength) n16 += advance;
}
return s.toString().substring(0,n16);
}
}
And a test class for it:
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class ZoneTrimTransformerTest {
#Test
public void testLengths()
{
ZoneTrimTransformer lztr = new ZoneTrimTransformer(5);
assertEquals(lztr.transform("İİİİİİİİİİ"),"İİ");
assertEquals(lztr.getDBRequireLength(lztr.transform("İİİİİİİİİİ").toString()),4);
assertEquals(lztr.getJavaLength(lztr.transform("İİİİİİİİİİ").toString()),2);
assertEquals(lztr.transform("%&*%$^&$$^&$").toString(),"%&*%$");
assertEquals(lztr.getDBRequireLength(("%&*%$^&$$^&$").toString()),12);
assertEquals(lztr.getJavaLength(("%&*%$^&$$^&$").toString()),12);
assertEquals(lztr.transform("媒体アカウント名"),"媒");
assertEquals(lztr.getDBRequireLength(("媒体アカウント名").toString()),24);
assertEquals(lztr.getJavaLength(("媒体アカウント名").toString()),8);
assertEquals(lztr.transform("媒体媒体アカウント名アカウント名"),"媒");
assertEquals(lztr.getDBRequireLength(("媒体媒体アカウント名アカウント名").toString()),48);
assertEquals(lztr.getJavaLength(("媒体媒体アカウント名アカウント名").toString()),16);
assertEquals(lztr.transform("SÄ°STA+UNÄ°VERSAL"),"SÄ°");
assertEquals(lztr.getDBRequireLength(("SÄ°STA+UNÄ°VERSAL").toString()),21);
assertEquals(lztr.getJavaLength(("SÄ°STA+UNÄ°VERSAL").toString()),17);
assertEquals(lztr.transform("1234567890"),"12345");
assertEquals(lztr.getDBRequireLength(("1234567890").toString()),10);
assertEquals(lztr.getJavaLength(("1234567890").toString()),10);
assertEquals(lztr.transform("abcdefghI"),"abcde");
assertEquals(lztr.getDBRequireLength(("abcdefghI").toString()),9);
assertEquals(lztr.getJavaLength(("abcdefghI").toString()),9);
assertEquals(lztr.transform("אהגדהוזחט"),"אה");
assertEquals(lztr.getDBRequireLength(("אהגדהוזחט").toString()),18);
assertEquals(lztr.getJavaLength(("אהגדהוזחט").toString()),9);
assertEquals(lztr.transform("ABAA"),"ABAA");
assertEquals(lztr.getDBRequireLength(("ABAA").toString()),4);
assertEquals(lztr.getJavaLength(("ABAA").toString()),4);
assertEquals(lztr.getDBRequireLength(lztr.transform("ABCE").toString()),4);
assertEquals(lztr.getJavaLength(lztr.transform("ABCE").toString()),4);
}
}
I want to time how long my code takes to perform on average over many test runs. In each test run, doWork() performs the work that I want to time. But I also want to checkWork() in each test run without it counting towards the time. I'm going to have many similar Exercise# classes, so I'd like to abstract the testing via a TestInterface. Is my current way a reasonable approach? Or is there a better design pattern / standard approach? Thanks in advance.
#FunctionalInterface
public interface TestInterface {
void test(final int NUM_TESTS);
}
public class TimeTests {
public static void test(TestInterface ti, final int NUM_TESTS, String testName) {
DecimalFormat df = new DecimalFormat("#.####");
long start = System.nanoTime();
ti.test(NUM_TESTS);
System.out.println("DEBUG: " + testName + " took "
+ df.format((System.nanoTime() - start) * 1.0 / NUM_TESTS)
+ " nanoseconds on average for " + NUM_TESTS + " tests");
}
}
public class Exercise1 {
private static final int NUM_TESTS = (int) Math.pow(10, 6);
private static void mainWork(List<Integer> A) {
// do stuff and time it
}
private static void checkWork(List<Integer> A) {
// do stuff but don't count it towards the time
}
public static void main(String[] args) {
TimeTests.test((NUM_TESTS_LOCAL) -> {
for (int i = 0; i < NUM_TESTS_LOCAL; ++i) {
List<Integer> A = new ArrayList<>();
// add random elements to A
mainWork(A);
checkWork(A);
}
}, NUM_TESTS, "Exercise1");
}
}
Okay, I think I managed to put together a decent framework (is this the right word?) for this task. If anybody could chime in to let me know if my approach is any good, I'd really appreciate it.
While my code seems to work fine for my use cases so far, I have a few questions:
In the interface definition of public interface CloneableTestInput<T extends CloneableTestInput<T>>, how is the type template <T extends CloneableTestInput<T> not a circular definition? I'm not sure I fully understand what that type template is saying.
Is there a way to make a generic CloneableList class that implements CloneableTestInput<List>? Currently, I need to make a separate implementation for each Collection type (e.g. ArrayList, LinkedList, ...). Similarly, is it possible to make a generic CloneableSet class that implements CloneableTestInput<Set>?
Thanks in advance :)
Testing Framework
Part I - An interface for test inputs
This allows TimeTests.java to work for generic input types.
public interface CloneableTestInput<T extends CloneableTestInput<T>> extends Cloneable {
T clone();
}
public class CloneableString implements CloneableTestInput<CloneableString> {
public String data;
public CloneableString() {}
public CloneableString(String input) { data = input; }
public CloneableString clone() { return new CloneableString(String.valueOf(data)); }
}
public class CloneableArrayList extends ArrayList implements CloneableTestInput<CloneableArrayList> {
public CloneableArrayList(ArrayList input) {
this.addAll(input);
}
#Override
public CloneableArrayList clone() {
return new CloneableArrayList(this);
}
}
Part II - An interface for timing tests
#FunctionalInterface
public interface TimeTestsInterface<outputType> {
void test(Callable<CloneableTestInput> formInput
, Function<CloneableTestInput, outputType> runAlgorithm
, Function<CloneableTestInput, outputType> getKnownOutput
, BiFunction<outputType, outputType, Boolean> checkResults
, final int NUM_TESTS, String testName);
}
public class TimeTests<outputType> implements TimeTestsInterface<outputType> {
public void test(Callable<CloneableTestInput> formInput
, Function<CloneableTestInput, outputType> runAlgorithm
, Function<CloneableTestInput, outputType> getKnownOutput
, BiFunction<outputType, outputType, Boolean> checkResults
, final int NUM_TESTS, String testName) {
try {
DecimalFormat df = new DecimalFormat("#.####");
long total = 0, start;
for (int i=0; i < NUM_TESTS; ++i) {
CloneableTestInput input = formInput.call();
CloneableTestInput orig_input = input.clone();
start = System.nanoTime();
outputType algorithmResult = runAlgorithm.apply(input);
total += System.nanoTime() - start;
outputType expectedResult = getKnownOutput.apply(orig_input);
assert(checkResults.apply(algorithmResult, expectedResult));
}
System.out.println("DEBUG: " + testName + " took "
+ df.format(total * 1.0 / NUM_TESTS)
+ " nanoseconds on average for " + NUM_TESTS + " tests");
} catch (Exception|AssertionError e) {
System.out.println(e.toString() + " - " + e.getMessage() + " - ");
e.printStackTrace();
}
}
}
Example Usages
Increment a BigInteger (uses CloneableArrayList)
/**
* Problem 6.2 from EPI
* Given an array A of digits encodiing a decimal number D,
* with MSD at A[0]. Update A to hold D + 1.
*/
public class PlusOne {
private static final int NUM_TESTS = (int) Math.pow(10, 5);
private static final int ARR_LENGTH = (int) Math.pow(10, 2);
private static ArrayList<Integer> plusOne(ArrayList<Integer> A) {
int n = A.size() - 1;
A.set(n, A.get(n) + 1);
for (int i = n; i > 0 && A.get(i) == 10; --i) {
A.set(i, 0);
A.set(i-1, A.get(i-1) + 1);
}
if (A.get(0) == 10) {
// Need additional digit up front as MSD
A.set(0,0);
A.add(0,1);
}
return A;
}
private static ArrayList<Integer> randArray(int len) {
ArrayList<Integer> A = new ArrayList<>();
if (len == 0) return A;
Random rgen = new Random();
A.add(rgen.nextInt(9) + 1);
--len;
while (len != 0) {
A.add(rgen.nextInt(10));
--len;
}
return A;
}
public static void main(String[] args) {
Callable<CloneableTestInput> formInput = () -> new CloneableArrayList(randArray(ARR_LENGTH));
Function<CloneableTestInput, ArrayList<Integer>> runAlgorithm =
(input) -> plusOne((ArrayList<Integer>) input);
Function<CloneableTestInput, ArrayList<Integer>> getKnownOutput =
(orig_input) -> {
BigInteger B = new BigInteger(Joiner.on("").join((ArrayList<Integer>) orig_input));
B = B.add(BigInteger.valueOf(1));
ArrayList<Integer> expectedOutput = new ArrayList<>();
while (B.compareTo(BigInteger.valueOf(0)) > 0) {
expectedOutput.add(0, B.mod(BigInteger.valueOf(10)).intValue());
B = B.divide(BigInteger.valueOf(10));
}
return expectedOutput;
};
BiFunction<ArrayList<Integer>, ArrayList<Integer>, Boolean> checkResults = List::equals;
TimeTests<ArrayList<Integer>> algTimer = new TimeTests<>();
algTimer.test(formInput, runAlgorithm, getKnownOutput, checkResults, NUM_TESTS, "PlusOne");
}
}
Can String be rearranged as a palindrome? (uses CloneableString)
public class CanStringBePalindrome {
private static final int INPUT_STRING_LENGTH = (int) Math.pow(10, 2);
private static final int NUM_TESTS = (int) Math.pow(10, 6);
private static boolean canFormPalindromeHash(final String s) {
Map<Character, Integer> charFreqs = new HashMap<>();
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
if (!charFreqs.containsKey(c))
charFreqs.put(c, 1);
else
charFreqs.put(c, charFreqs.get(c) + 1);
}
int oddFreqCount = 0;
for (Map.Entry<Character, Integer> entry : charFreqs.entrySet()) {
if ((entry.getValue() % 2) != 0 && (++oddFreqCount > 1))
return false;
}
return true;
}
private static boolean canFormPalindromeSorting(final String s) {
// TODO : find faster/simpler way of getting frequency counts
char[] a = s.toCharArray();
Arrays.sort(a);
int oddFreqCount = 0;
int numCurrChar =1;
for (int i = 1; i < a.length && oddFreqCount <= 1; ++i) {
if(a[i] != a[i-1]) {
if ((numCurrChar & 1) != 0)
++oddFreqCount;
numCurrChar = 1;
} else
++numCurrChar;
}
if ((numCurrChar & 1) != 0)
++oddFreqCount;
return oddFreqCount <= 1;
}
private static String randString(int len) {
StringBuilder sb = new StringBuilder();
Random rgen = new Random();
while (len-- > 0)
sb.append((char)(rgen.nextInt(26) + 'A'));
return sb.toString();
}
public static void main(String[] args) {
Callable<CloneableTestInput> formInput = () -> new CloneableString(randString(INPUT_STRING_LENGTH));
Function<CloneableTestInput, Boolean > runAlgorithm =
(input) -> canFormPalindromeHash(((CloneableString)input).data);
Function<CloneableTestInput, Boolean> getKnownOutput =
(orig_input) -> canFormPalindromeSorting(((CloneableString)orig_input).data);
BiFunction<Boolean, Boolean, Boolean> checkResults = Boolean::equals;
TimeTests<Boolean> algTimer = new TimeTests<>();
algTimer.test(formInput, runAlgorithm, getKnownOutput, checkResults
, NUM_TESTS, "CanStringBePalindrome");
}
}
I know that "printf" method can use string formatting.
My question is :
Is there a way to create a nice looking table with StringBuilder class?
For example:
|Id|Category|Level|Space|Type|Adress|Dimension|Limits|
And under that row, i must add the values of each columns!
Doing something like that : example but with StringBuilder
So the community want to see my answer (which i don't understand why ... but any way i will put it !)
public String toString(){
StringBuilder s = new StringBuilder();
s.append("Category: "+this.category+"\t");
s.append("Level: "+this.level.toString()+"\t");
return s.toString();
}
Now explain me, why seeing my answer will help me ? I really want to see your answer !
A simple approach is, of course, to create hard-wired printf statements. However, this is not very flexible, because you always have to fix the column widths, and the functions will always be specific for one class and its fields.
So I'd like to propose a helper class that mainly does two things:
Encapsulates the creation of table cell entries (via a Java 8 Function)
Computes the maximum width of each columnm for a given set of elements.
Let there be a given model class, like a Person, for example:
class Person
{
int getId() { ... }
String getFirstName() { ... }
String getLastName() { ... }
float getHeight() { ... }
}
Then, I'd like to create a "nice" table as follows:
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
And I'd expect the contents of this string to be a nicely formatted table:
id| first name| last name|height
-----+-------------+-------------+------
41360|Xvnjhpdqdxvcr| Stvybcwvm| 1.7
3503| Krxvzxk| Xtspsjd| 1.6
41198| Uegqfl| Qlocfljbepo| 1.58
26517| Somyar| Aopufo| 1.77
13773| Dxehxjbhwgsm| Jgnlonjv| 1.77
13067| Zozitk| Jbozwd| 1.81
46534| Bosyq| Kcprrdc| 1.55
93862| Rlfxblgqp| Pgrntaqoos| 1.85
12155| Kjpjlavsqc|Rxfrrollhwhoh| 1.79
75712| Fwpnd| Mwcsshwx| 1.78
Here is a MVCE that shows such a TableStringBuilder and its application:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
public class TableStringTest
{
public static void main(String[] args)
{
List<Person> persons = new ArrayList<Person>();
for (int i=0; i<10; i++)
{
persons.add(new Person());
}
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
System.out.println(s);
}
}
class TableStringBuilder<T>
{
private final List<String> columnNames;
private final List<Function<? super T, String>> stringFunctions;
TableStringBuilder()
{
columnNames = new ArrayList<String>();
stringFunctions = new ArrayList<Function<? super T, String>>();
}
void addColumn(String columnName, Function<? super T, ?> fieldFunction)
{
columnNames.add(columnName);
stringFunctions.add((p) -> (String.valueOf(fieldFunction.apply(p))));
}
private int computeMaxWidth(int column, Iterable<? extends T> elements)
{
int n = columnNames.get(column).length();
Function<? super T, String> f = stringFunctions.get(column);
for (T element : elements)
{
String s = f.apply(element);
n = Math.max(n, s.length());
}
return n;
}
private static String padLeft(String s, char c, int length)
{
while (s.length() < length)
{
s = c + s;
}
return s;
}
private List<Integer> computeColumnWidths(Iterable<? extends T> elements)
{
List<Integer> columnWidths = new ArrayList<Integer>();
for (int c=0; c<columnNames.size(); c++)
{
int maxWidth = computeMaxWidth(c, elements);
columnWidths.add(maxWidth);
}
return columnWidths;
}
public String createString(Iterable<? extends T> elements)
{
List<Integer> columnWidths = computeColumnWidths(elements);
StringBuilder sb = new StringBuilder();
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
sb.append(String.format(format, columnNames.get(c)));
}
sb.append("\n");
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("+");
}
sb.append(padLeft("", '-', columnWidths.get(c)));
}
sb.append("\n");
for (T element : elements)
{
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
Function<? super T, String> f = stringFunctions.get(c);
String s = f.apply(element);
sb.append(String.format(format, s));
}
sb.append("\n");
}
return sb.toString();
}
}
//Dummy Person Class
class Person
{
private int id;
private String firstName;
private String lastName;
private float height;
private static Random random = new Random(0);
Person()
{
id = random.nextInt(100000);
firstName = createRandomString();
lastName = createRandomString();
height = (150 + random.nextInt(40)) / 100.0f;
}
private static String createRandomString()
{
int length = random.nextInt(10) + 5;
StringBuilder sb = new StringBuilder();
char offset = 'A';
for (int i=0; i<length; i++)
{
char c = (char)(random.nextInt(26) + offset);
sb.append(c);
offset = 'a';
}
return sb.toString();
}
int getId()
{
return id;
}
String getFirstName()
{
return firstName;
}
String getLastName()
{
return lastName;
}
float getHeight()
{
return height;
}
}
Ok, so thank you for all the answer who was nice to me.
I figured out that we could do it by that way :
public String toString(){
StringBuilder s = new StringBuilder();
s.append(String.format("%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n","Identifier","Category","Level","Space","Type","Dimension","Limits"));
s.append(String.format("=============================================================================================================================================\n"));
for(String id : this.idTable.keySet()) {
s.append(String.format("%-20s",id));
s.append(this.idTable.get(id).toString());
//s.append("Identifier: " +id+" "+this.idTable.get(id).toString()+"\n");
}
return s.toString();
}
Notice, the String.format which do all the work i wanted and didn't know before !
Regardind to you #Marco13, You did a very good job !!!!
Thanks all !
P.S.: I will aprove the message from #Marco13 , because his implementation is very good also !
I want to list dates from the most current date to the oldest date.
I don't want to use Collections.sort()so I made my own method.
When I do this :
List<Livre> maBibliotheque = new ArrayList<Livre>();
boolean tri = false;
int born = maBibliotheque.size();
while (tri == false)
{
tri = true ;
for (int i=0; i<born-1;i++)
{
if ( maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i+1).getNewPeriode())>0){
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i+1));
maBibliotheque.set(i+1,livre);
tri = false ; }
}
born -= born;
}
It works perfectly, but from the oldest to the newest date, but I want the otherwise.
I change this line to
if ( maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i+1).getNewPeriode())<0){
But it's doesn't make anything, no sort dates in this case. Please help
To reverse the order, replace > 0 with < 0
Doesn't
born -= born;
do the same as
born = 0;
I suspect this isn't needed.
This
public static void main(String[] args) throws IOException, IllegalAccessException, NoSuchFieldException {
List<Livre> maBibliotheque = new ArrayList<Livre>();
maBibliotheque.add(new Livre("aaa"));
maBibliotheque.add(new Livre("abb"));
maBibliotheque.add(new Livre("bbb"));
maBibliotheque.add(new Livre("000"));
boolean tri;
int born = maBibliotheque.size();
do {
tri = true;
for (int i = 0; i < born - 1; i++) {
if (maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i + 1).getNewPeriode()) > 0) {
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i + 1));
maBibliotheque.set(i + 1, livre);
tri = false;
}
}
} while (!tri);
System.out.println("increasing: " + maBibliotheque);
do {
tri = true;
for (int i = 0; i < born - 1; i++) {
if (maBibliotheque.get(i).getNewPeriode().compareTo(maBibliotheque.get(i + 1).getNewPeriode()) < 0) {
Livre livre = maBibliotheque.get(i);
maBibliotheque.set(i, maBibliotheque.get(i + 1));
maBibliotheque.set(i + 1, livre);
tri = false;
}
}
} while (!tri);
System.out.println("decreasing: " + maBibliotheque);
}
static class Livre {
private final String newPeriode;
Livre(String newPeriode) {
this.newPeriode = newPeriode;
}
public String getNewPeriode() {
return newPeriode;
}
#Override
public String toString() {
return "Livre{" +
"newPeriode='" + newPeriode + '\'' +
'}';
}
}
prints
increasing: [Livre{newPeriode='000'}, Livre{newPeriode='aaa'}, Livre{newPeriode='abb'}, Livre{newPeriode='bbb'}]
decreasing: [Livre{newPeriode='bbb'}, Livre{newPeriode='abb'}, Livre{newPeriode='aaa'}, Livre{newPeriode='000'}]
Sort from oldest to newest, then reverse it with Collections.reverse(maBibliotheque);
I would recommend implementing a Comparator. You set a field in the Comparator object that can tell it whether to sort Ascending or Descending, then call Collections.sort(maBibliotheque, new MyComparator(MyComparator.DESC))
Demo (adjust generics as needed, and if, as in this case, you know that you're comparing with a specific field use o1.getField().compareTo(o2.getField()). Alternately, you could implement Comparable in your Object and just call Collections.sort(List), but that's not as flexible.
public class MyComparator implements Comparator<String>
{
public static final int ASC = 0;
public static final int DESC = 1;
private final int sortOrder;
public MyComparator(int sortOrder)
{
this.sortOrder = sortOrder;
}
/* (non-Javadoc)
* #see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
#Override
public int compare(String o1, String o2)
{
switch(this.sortOrder)
{
case ASC:
return o1.compareTo(o2);
case DESC:
return o2.compareTo(o1);
}
return 0;
}
}