Encoding a date into an ASCII barcode - date

I am investigating encoding of date information into a linear barcode that must be as short as possible. One idea we have had is encoding date information rather than using the ASCII characters for the date numerals.
The earliest date to be encoded is 01-JAN-2009
Date must be encoded using printable ASCII characters

If only the date matters (not the time):
Take the date to be encoded.
Subtract 1-1-2009 from it
Get the amount of elapsed days.
To encode this number as a printable sequence of ascii chars(ascii 48-127) do the following
pseudo code:
const int ASCIILOWRANGE = 48
const int ASCIIHIGHRANGE = 126
const char ASCIIENDMARKER = 127;
String convertToAscii(int numberOfDays)
{
String output = "";
while(numberOfDays>0)
{
output += (char) ASCIILOWRANGE + numberOfDays % (ASCIIHIGHRANGE-ASCIILOWRANGE);
numberOfDays /= (ASCIIHIGHRANGE-ASCIILOWRANGE);
}
output += ASCIIENDMARKER ;
return output;
}
//decoder
int convertToDays(String ascii)
{
char rightmost;
int numberOfDays = 0;
while(ascii.length>0)
{
rightmost = ascii[0];
if(rightmost == ASCIIENDMARKER ) break; //ready
numberOfDays *= (rightmost - ASCIILOWRANGE) * (ASCIIHIGHRANGE-ASCIILOWRANGE);
ascii = ascii.substr(1); //remove rightmost char from string
}
return numberOfDays ;
}
this way of encoding is the most dense. Since it encodes upto 96 days into the future in just 2 chars. 9216 days, in 3 chars, 884736 days in 4 chars.

Use the date itself: 01/01/2009 is a perfectly acceptable barcode under the Code39 style barcode.
If you don't mind a bit of processing logic during read, then you can do things like remove the "/" or whatever separator character you use.
Basically you would encode something like, "01012009" into the barcode, and then have the decode process just read the first two numbers as the month, the next two as the day, and the last 4 as the year. Since they're straight ascii it will work without any really hard processing.
A second alternative is to have 01-Jan-2009 as your "0" date, and then just encode the number of days since then. At which the decoding process would be to read the number, and then add that many days to 1/1/09. This would work that, Jan/5/2009 would be encoded as a "4" then when you wanted to read the date back out, you'd add 4 to Jan/1/09 to get Jan/5/09.

Related

Parse military time to double in flutter

I am trying to convert a textfield input of military time into a double. Can anyone help me with this? goal would be if someone enters 13:45 then the output would be 13.75.
Divide your input into 2 halves around the :. Then parse each half, which results in separate hours and minutes ints. Add them together, dividing the minutes by 60 to get your intended double output.
String input = "13:45";
String firstHalf = input.substring(0, input.indexOf(':'));
String secHalf = input.substring(input.indexOf(':') + 1);
int hour = int.parse(firstHalf);
int min = int.parse(secHalf);
double output = hour + min/60;
print(output);//13.75

Swift 5: String prefix with a maximum UTF-8 length

I have a string that can contain arbitrary Unicode characters and I want to get a prefix of that string whose UTF-8 encoded length is as close as possible to 32 bytes, while still being valid UTF-8 and without changing the characters' meaning (i.e. not cutting off an extended grapheme cluster).
Consider this CORRECT example:
let string = "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}\u{1F1EA}\u{1F1FA}"
print(string) // 🏴󠁧󠁒󠁳󠁣󠁴󠁿πŸ‡ͺπŸ‡Ί
print(string.count) // 2
print(string.utf8.count) // 36
let prefix = string.utf8Prefix(32) // <-- function I want to implement
print(prefix) // 🏴󠁧󠁒󠁳󠁣󠁴󠁿
print(prefix.count) // 1
print(prefix.utf8.count) // 28
print(string.hasPrefix(prefix)) // true
And this example of a WRONG implementation:
let string = "ar\u{1F3F4}\u{200D}\u{2620}\u{FE0F}\u{1F3F4}\u{200D}\u{2620}\u{FE0F}\u{1F3F4}\u{200D}\u{2620}\u{FE0F}"
print(string) // arπŸ΄β€β˜ οΈπŸ΄β€β˜ οΈπŸ΄β€β˜ οΈ
print(string.count) // 5
print(string.utf8.count) // 41
let prefix = string.wrongUTF8Prefix(32) // <-- wrong implementation
print(prefix) // arπŸ΄β€β˜ οΈπŸ΄β€β˜ οΈπŸ΄
print(prefix.count) // 5
print(prefix.utf8.count) // 32
print(string.hasPrefix(prefix)) // false
What's an elegant way to do this? (besides trial&error)
You've shown no attempt at a solution and SO doesn't normally write code for you. So instead here as some algorithm suggestions for you:
What's an elegant way to do this? (besides trial&error)
By what definition of elegant? (like beauty it depends on the eye of the beholder...)
Simple?
Start with String.makeIterator, write a while loop, append Characters to your prefix as long as the byte count ≀ 32.
It's a very simple loop, worse case is 32 iterations and 32 appends.
"Smart" Search Strategy?
You could implement a strategy based on the average byte length of each Character in the String and using String.Prefix(Int).
E.g. for your first example the character count is 2 and the byte count 36, giving an average of 18 bytes/character, 18 goes into 32 just once (we don't deal in fractional characters or bytes!) so start with Prefix(1), which has a byte count of 28 and leaves 1 character and 8 bytes – so the remainder has an average byte length of 8 and you are seeking at most 4 more bytes, 8 goes into 4 zero times and you are done.
The above example shows the case of extending (or not) your prefix guess. If your prefix guess is too long you can just start your algorithm from scratch using the prefix character & byte counts rather than the original string's.
If you have trouble implementing your algorithm ask a new question showing the code you've written, describe the issue, and someone will undoubtedly help you with the next step.
HTH
I discovered that String and String.UTF8View share the same indices, so I managed to create a very simple (and efficient?) solution, I think:
extension String {
func utf8Prefix(_ maxLength: Int) -> Substring {
if self.utf8.count <= maxLength {
return Substring(self)
}
var index = self.utf8.index(self.startIndex, offsetBy: maxLength+1)
self.formIndex(before: &index)
return self.prefix(upTo: index)
}
}
Explanation (assuming maxLength == 32 and startIndex == 0):
The first case (utf8.count <= maxLength) should be clear, that's where no work is needed.
For the second case we first get the utf8-index 33, which is either
A: the endIndex of the string (if it's exactly 33 bytes long),
B: an index at the start of a character (after 33 bytes of previous characters)
C: an index somewhere in the middle of a character (after <33 bytes of previous characters)
So if we now move our index back one character (with formIndex(before:)) this will jump to the first extended grapheme cluster boundary before index which in case A and B is one character before and in C the start of that character.
I any case, the utf8-index will now be guaranteed to be at most 32 and at an extended grapheme cluster boundary, so prefix(upTo: index) will safely create a prefix with length ≀32.
…but it's not perfect.
In theory this should also be always the optimal solution, i.e. the prefix's count is as close as possible to maxLength but sometimes when the string ends with an extended grapheme cluster consisting of more than one Unicode scalar, formIndex(before: &index) goes back one character too many than would be necessary, so the prefix ends up shorter. I'm not exactly sure why that's the case.
EDIT: A not as elegant but in exchange completely "correct" solution would be this (still only O(n)):
extension String {
func utf8Prefix(_ maxLength: Int) -> Substring {
if self.utf8.count <= maxLength {
return Substring(self)
}
let endIndex = self.utf8.index(self.startIndex, offsetBy: maxLength)
var index = self.startIndex
while index <= endIndex {
self.formIndex(after: &index)
}
self.formIndex(before: &index)
return self.prefix(upTo: index)
}
}
I like the first solution you came up with. I've found it works more correctly (and simpler) if you take out the formIndex:
extension String {
func utf8Prefix(_ maxLength: Int) -> Substring {
if self.utf8.count <= maxLength {
return Substring(self)
}
let index = self.utf8.index(self.startIndex, offsetBy: maxLength)
return self.prefix(upTo: index)
}
}
My solution looks like this:
extension String {
func prefix(maxUTF8Length: Int) -> String {
if self.utf8.count <= maxUTF8Length { return self }
var utf8EndIndex = self.utf8.index(self.utf8.startIndex, offsetBy: maxUTF8Length)
while utf8EndIndex > self.utf8.startIndex {
if let stringIndex = utf8EndIndex.samePosition(in: self) {
return String(self[..<stringIndex])
} else {
self.utf8.formIndex(before: &utf8EndIndex)
}
}
return ""
}
}
It takes the highest possible utf8 index, checks if it is a valid character index using the Index.samePosition(in:) method. If not, it reduces the utf8 index one by one until it finds a valid character index.
The advantage is that you could replace utf8 with utf16 and it would also work.

Comparing date by combining it

Im just wondering. is it ok to combine years,month, and day of two date and make a comparison based on the combination.
eg:
Date A: 12th-January-2019
Date B: 24th-December-2018
Based on the above date, i could combine the year,month, and day as follow:
Date A: 20190112
Date B: 20181224
So based on the numbers, i could do logic like below to compare which date comes first:
if(Date A > Date B) {
output("Date A is the latest")
}
i would like to implement this method just to compare which is the latest date.
are there any problem of doing so.
java.time
Since you are using Java, I suggest that you take advantage of java.time, the modern Java date and time API.
String[] dateStringsFromDatabase = {
"2018/12/19",
"2017-02-01",
"2018.03.04",
"25-12-2016", // reversed
"2019\\09\\12",
"2014:03:01"
};
List<LocalDate> parsedDates = new ArrayList<>(dateStringsFromDatabase.length);
for (String dateString : dateStringsFromDatabase) {
// No matter which delimiter is used, replace it with a hyphen
String text = dateString.replaceAll("\\W", "-");
try {
parsedDates.add(LocalDate.parse(text));
} catch (DateTimeParseException dtpe) {
System.out.println(dateString + " not parsed: " + dtpe.getMessage());
}
}
Output:
25-12-2016 not parsed: Text '25-12-2016' could not be parsed at index 0
What this approach buys you is validation of the dates even though they come with all different delimiters. Especially in this situation I believe that you should want to validate that your strings are within the expected variations. Otherwise you risk that a date with the numbers reversed ends up as a date in year 2512, for example. You want to catch that before it happens.
Example of comparing which comes first:
for (int i = 1; i < parsedDates.size(); i++) {
LocalDate dateA = parsedDates.get(i - 1);
LocalDate dateB = parsedDates.get(i);
if (dateA.isAfter(dateB)) {
System.out.format("%s is later than %s%n", dateA, dateB);
}
}
Output:
2018-12-19 is later than 2017-02-01
2019-09-12 is later than 2014-03-01
Link: Oracle tutorial: Date Time explaining how to use java.time.

Number validation and formatting

I want to format, in real time, the number entered into a UITextField. Depending on the field, the number may be an integer or a double, may be positive or negative.
Integers are easy (see below).
Doubles should be displayed exactly as the user enters with three possible exceptions:
If the user begins with a decimal separator, or a negative sign followed by a decimal separator, insert a leading zero:
"." becomes "0."
"-." becomes "-0."
Remove any "excess" leading zeros if the user deletes a decimal point:
If the number is "0.00023" and the decimal point is deleted, the number should become "23".
Do not allow a leading zero if the next character is not a decimal separator:
"03" becomes "3".
Long story short, one and only one leading zero, no trailing zeros.
It seemed like the easiest idea was to convert the (already validated) string to a number then use format specifiers. I've scoured:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
and
http://www.cplusplus.com/reference/cstdio/printf/
and others but can't figure out how to format a double so that it does not add a decimal when there are no digits after it, or any trailing zeros. For example:
x = 23.0
print (String(format: "%f", x))
//output is 23.000000
//I want 23
x = 23.45
print (String(format: "%f", x))
//output is 23.450000
//I want 23.45
On How to create a string with format?, I found this gem:
var str = "\(INT_VALUE) , \(FLOAT_VALUE) , \(DOUBLE_VALUE), \(STRING_VALUE)"
print(str)
It works perfectly for integers (why I said integers are easy above), but for doubles it appends a ".0" onto the first character the user enters. (It does work perfectly in Playground, but not my program (why???).
Will I have to resort to counting the number of digits before and after the decimal separator and inserting them into a format specifier? (And if so, how do I count those? I know how to create the format specifier.) Or is there a really simple way or a quick fix to use that one-liner above?
Thanks!
Turned out to be simple without using NumberFormatter (which I'm not so sure would really have accomplished what I want without a LOT more work).
let decimalSeparator = NSLocale.current.decimalSeparator! as String
var tempStr: String = textField.text
var i: Int = tempStr.count
//remove leading zeros for positive numbers (integer or real)
if i > 1 {
while (tempStr[0] == "0" && tempStr[1] != decimalSeparator[0] ) {
tempStr.remove(at: tempStr.startIndex)
i = i - 1
if i < 2 {
break
}
}
}
//remove leading zeros for negative numbers (integer or real)
if i > 2 {
while (tempStr[0] == "-" && tempStr[1] == "0") && tempStr[2] != decimalSeparator[0] {
tempStr.remove(at: tempStr.index(tempStr.startIndex, offsetBy: 1))
i = i - 1
if i < 3 {
break
}
}
}
Using the following extension to subscript the string:
extension String {
subscript (i: Int) -> Character {
return self[index(startIndex, offsetBy: i)]
}
}

converting an int to a string in Objective-C while preserving '0'

I am trying to convert an int to a string in objective-C.
I read the other questions on SO about converting ints to strings, and I tried this method in my code:
-(void)setCounter:(int)count
{
counterText.text = [NSString stringWithFormat:#"%d",count];
}
However, if I want to display a number like '01' the 0 is taken out of the conversion and only '1' is displayed. Is there a workaround?
There is no such number as 01. If you write
int count = 01;
it is compiled equivalently to
int count = 1;
In fact, be careful: 07 is equivalent to 7, but 011 is equivalent to 9!
What you can do is ask stringWithFormat: to give you the zero-padding:
[NSString stringWithFormat:#"%02d",count]
should give you "02" if count is 2. To deconstruct it:
% - interpolate the next value here
0 - pad it to the width by placing zeroes on the left side
2 - width is 2 characters
d - it will be an integer. Do it now.
If you want a different format to the one shown, use it:
counterText.text = [NSString stringWithFormat:#"%02d",count];
There are a huge range of possibilities with the format string.
if any number start from 0 then Its a octal representation (0 - 7). you can add zero explictly using below line.
counterText.text = [NSString stringWithFormat:#"0%d",count];
Check out..
NSNumber +numberWithInt
and then:
NSNumberFormatter -setMinimumIntegerDigits
and then get the string representation with:
NSString -stringFromNumber