How to convert UPC-A to UPC-E? - ios

We would like to convert the 12 digit UPC-A to 8 digit UPC-E. Can you tell me which is the best way to do this without having to use my own code to convert?
I got many formula for convert the 8 digit UCC-E to 12 digit UPC-A but not reverse.

The algorithm for converting a GTIN-12 identifier between UPC-A and UPC-E representation can be most clearly seen from the following pattern mapping:
SabN0000cdeX ⟺ SabcdeNX : 0≤N≤2
Sabc00000deX ⟺ Sabcde3X
Sabcd00000eX ⟺ Sabcde4X
Sabcde0000NX ⟺ SabcdeNX : 5≤N≤9
In the above S is the number system, either 0 or 1 and X is the check digit. If a UPC-A doesn't match a pattern then it cannot be converted to UPC-E.
It can be seen that there may be up to four valid UPC-E representations of each UPC-A:
001200000067 ⟺ 00100627 ⟺ 00120637 ⟺ 00120647 ⟺ 00120067.
Pseudo-code performing one method of conversion from UPC-A to UPC-E looks like this:
Input: A valid twelve-digit UPC-A: Assigned to A[].
Output: PASS: Eight-digit UPC-E representing the UPC-A.
FAIL: Reason.
if A[0] != {0-1} then FAIL: Invalid number system.
if A[3] == {0-2} && A[4..7] == "0000" then PASS: A[0..2] . A[8..10] . A[3] . A[11]
if A[4..8] == "00000" then PASS: A[0..3] . A[9..10] . "3" . A[11]
if A[5..9] == "00000" then PASS: A[0..4] . A[10] . "4" . A[11]
if A[6..9] == "0000" && A[10] == {5-9} then PASS: A[0..5] . A[10] . A[11]
otherwise, FAIL: UPC-A not compatible with UPC-E.

NSString *strScannedCode = #"028200002921";
NSString *strBarCodeType = #"UPC E";
NSString *strAlteredScannedCode = strScannedCode;
if ([strBarCodeType isEqualToString:#"UPC E"])
{
if (strScannedCode.length == 12)
{
NSString *strManufacturerCode = [strScannedCode substringWithRange:(NSMakeRange(1, 5))];
NSString *strProductCode = [strScannedCode substringWithRange:NSMakeRange(6, 5)];
NSLog(#"strManufacturerCode = %#",strManufacturerCode);
NSLog(#"strProductCode = %#",strProductCode);
if ([[strManufacturerCode substringWithRange:NSMakeRange(2, 3)] isEqualToString:#"000"] ||
[[strManufacturerCode substringWithRange:NSMakeRange(2, 3)] isEqualToString:#"100"] ||
[[strManufacturerCode substringWithRange:NSMakeRange(2, 3)] isEqualToString:#"200"])
{
strAlteredScannedCode = STRING(#"%#%#%#",[strManufacturerCode substringWithRange:NSMakeRange(0, 2)],
[strProductCode substringWithRange:NSMakeRange(2, 3)],
[strManufacturerCode substringWithRange:NSMakeRange(2, 1)]);
}
else if ([[strManufacturerCode substringWithRange:NSMakeRange(3, 2)] isEqualToString:#"00"])
{
strAlteredScannedCode = STRING(#"%#%#3",[strManufacturerCode substringWithRange:NSMakeRange(0, 3)],
[strProductCode substringWithRange:NSMakeRange(3, 2)]);
}
else if ([strManufacturerCode characterAtIndex:4] == '0')
{
strAlteredScannedCode = STRING(#"%#%#4",[strManufacturerCode substringWithRange:NSMakeRange(0, 4)],
[strProductCode substringWithRange:NSMakeRange(4, 1)]);
}
else if ([strManufacturerCode characterAtIndex:4] != '0')
{
strAlteredScannedCode = STRING(#"%#%#",strManufacturerCode,
[strProductCode substringWithRange:NSMakeRange(4, 1)]);
}
strAlteredScannedCode = STRING(#"%#%#%#",[strScannedCode substringWithRange:NSMakeRange(0, 1)],strAlteredScannedCode,[strScannedCode substringWithRange:NSMakeRange(11, 1)]);
NSLog(#"strUPC_E_Code = %#",strAlteredScannedCode);
}
}
By implementing above code you will get 12 digit to 8 digit, For Example you will get result as "02829221", This is UPC E of "028200002921".

Related

IBAN Validator Swift

I am writing an algorithm to validate IBAN (International Bank Account Number) in Swift 3 and not able to figure one of the validation.
Example IBAN - BE68539007547034
Here are the rules to validate -
Input number should be of length 16.
First 2 characters are country code (not numeric).
Last 14 are numeric.
Last 2 characters are the modulo 97 result of the previous 12 numeric characters.
While #1 - #3 are clear I need clarity on #4. If anyone have done this before and know about it then please let me know.
The validation algorithm is rather simple if you follow the algorithm on wikipedia:
extension String {
private func mod97() -> Int {
let symbols: [Character] = Array(self)
let swapped = symbols.dropFirst(4) + symbols.prefix(4)
let mod: Int = swapped.reduce(0) { (previousMod, char) in
let value = Int(String(char), radix: 36)! // "0" => 0, "A" => 10, "Z" => 35
let factor = value < 10 ? 10 : 100
return (factor * previousMod + value) % 97
}
return mod
}
func passesMod97Check() -> Bool {
guard self.characters.count >= 4 else {
return false
}
let uppercase = self.uppercased()
guard uppercase.range(of: "^[0-9A-Z]*$", options: .regularExpression) != nil else {
return false
}
return (uppercase.mod97() == 1)
}
}
Usage:
let iban = "XX0000000..."
let valid = iban.passesMod97Check()
If you want to validate the format for a specific country, just modify the regular expression, e.g.
"^[A-Z]{2}[0-9]{14}$"
or directly
"^BE\\d{14}$"
From Wikipedia
let IBAN = "GB82WEST12345698765432" // uppercase, no whitespace !!!!
var a = IBAN.utf8.map{ $0 }
while a.count < 4 {
a.append(0)
}
let b = a[4..<a.count] + a[0..<4]
let c = b.reduce(0) { (r, u) -> Int in
let i = Int(u)
return i > 64 ? (100 * r + i - 55) % 97: (10 * r + i - 48) % 97
}
print( "IBAN \(IBAN) is", c == 1 ? "valid": "invalid")
prints
IBAN GB82WEST12345698765432 is valid
With IBAN from your question it prints
IBAN BE68539007547034 is valid
I finded a great solution that work for me in Objective-C
https://gist.github.com/0xc010d/5301790 you can rewrite for Swift or use bridging header. Objective-C implementation of mod97 IBAN checking algorithm
#import <Foundation/Foundation.h>
#interface NSString (Mod97Check)
- (BOOL)passesMod97Check; // Returns result of mod 97 checking algorithm. Might be used to check IBAN.
// Expects string to contain digits and/or upper-/lowercase letters; space and all the rest symbols are not acceptable.
#end
#import "NSString+Mod97Check.h"
#implementation NSString (Mod97Check)
- (BOOL)passesMod97Check {
NSString *string = [self uppercaseString];
NSInteger mod = 0, length = [self length];
for (NSInteger index = 4; index < length + 4; index ++) {
unichar character = [string characterAtIndex:index % length];
if (character >= '0' && character <= '9') {
mod = (10 * mod + (character - '0')) % 97; // '0'=>0, '1'=>1, ..., '9'=>9
}
else if (character >= 'A' && character <= 'Z') {
mod = (100 * mod + (character - 'A' + 10)) % 97; // 'A'=>10, 'B'=>11, ..., 'Z'=>35
}
else {
return NO;
}
}
return (mod == 1);
}
#end
-(BOOL)isValidIBAN {
NSString *iban = self;
static NSString* const LettersAndDecimals = #"ABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789";
iban = [[iban stringByReplacingOccurrencesOfString:#" " withString:#""] uppercaseString];
NSCharacterSet *invalidChars = [[NSCharacterSet characterSetWithCharactersInString:LettersAndDecimals] invertedSet];
if ([iban rangeOfCharacterFromSet:invalidChars].location != NSNotFound)
{
return NO;
}
int checkDigit = [iban substringWithRange:NSMakeRange(2, 2)].intValue;
iban = [NSString stringWithFormat:#"%#%#",[iban substringWithRange:NSMakeRange(4, iban.length - 4)], [iban substringWithRange:NSMakeRange(0, 4)]] ;
for (int i = 0; i < iban.length; i++) {
unichar c = [iban characterAtIndex:i];
if (c >= 'A' && c <= 'Z') {
iban = [NSString stringWithFormat:#"%#%d%#", [iban substringWithRange:NSMakeRange(0, i)], (c - 'A' + 10),[iban substringWithRange:NSMakeRange(i+1, iban.length - i - 1)]];
}
}
iban = [[iban substringWithRange:NSMakeRange(0, iban.length - 2)] stringByAppendingString:#"00"];
while(true)
{
int iMin = (int)MIN(iban.length, 9);
NSString* strPart = [iban substringWithRange:NSMakeRange(0, iMin)];
int decnumber = strPart.intValue;
if(decnumber < 97 || iban.length < 3)
break;
int del = decnumber % 97;
iban = [NSString stringWithFormat:#"%d%#", del, [iban substringFromIndex:iMin]];
}
int check = 98 - iban.intValue;
return checkDigit == check;
}
Here you go :
func isValidIBAN(text:String) -> Bool {
let ibanRegEx = "[a-zA-Z]{2}+[0-9]{2}+[a-zA-Z0-9]{4}+[0-9]{7}([a-zA-Z0-9]?){0,16}"
let ibanTest = NSPredicate(format:"SELF MATCHES %#", ibanRegEx)
return ibanTest.evaluate(with: text)
}
It's clean, and it works.

IOS:Convert string to hexadecimal array

i have string representing data .i need to convert those data to the hex array .By using the hex array data i can pass it to the CRC for writing to the peripheral
My string data is like this
NSString *stringsdata=#"helloworld1234567812345q";
i need to convert to hex format array like
{0x0h,0x0e............0x0q}.
so by using this array i can keep the data in the crc and write it to the peripheral data as
Byte comm[24];
comm[0]=0x01;
comm[1]=0x30;
comm[2]=0x62;
comm[3]=0x00;................
have tried with many possible solutions but not luck.can any body help will be greatly appreciated.
A. The hexadecimal format is simply another representation of the same data.
B. You do not convert them into hex array. Every character has a number. For example in ASCII and UTF-8 the A has the number 65 (decimal representation). This is 0x41 in hex representation.
'A' (ASCII) == 65 == 0x41.
A hex number has the the digits 0-9, a-f, wherein a has the value of 10, b the value of 11 … It is converter into decimal representation by multiplying the upper digit by 16 and adding the lower digit. (0x41: 4 x 16 + 1 = 65.)
Please read and understand this: http://en.wikipedia.org/wiki/Hexadecimal
C. To convert a string into its number, you have to know, which code you want to apply. Probably you want to use UTF-8.
NSString *text = #"helloworld123123989128739";
NSUInteger length = [text lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
char data[length];
[text getCString:data maxLength:length usingEncoding:NSUTF8StringEncoding];
// Here we go
Byte[] class is an array of characters. I mean you can only set one character at it's index.
If we have
Byte comm[24]; then comm[0]=0x01; is looks like confusing here because it only saves one character.
And the statement will be like comm[0]='x';.
Below code will creates Byte[] from given string.
NSString *stringsdata=#"helloworld1234567812345q";
CFStringRef cfString = (__bridge CFStringRef)stringsdata;
char *array = charArrayFromCFStringRef(cfString);
size_t length= strlen(array);
Byte comm[24];
for (int i = 0; i < length; i++) {
comm[i] = array[i];
}
Conversion function:
char * charArrayFromCFStringRef(CFStringRef stringRef) {
if (stringRef == NULL) {
return NULL;
}
CFIndex length = CFStringGetLength(stringRef);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
char *buffer = (char *)malloc(maxSize);
if (CFStringGetCString(stringRef, buffer, maxSize, kCFStringEncodingUTF8)) {
return buffer;
}
return NULL;
}
OutPut:
Printing description of comm:
(Byte [24]) comm = {
[0] = 'h'
[1] = 'e'
[2] = 'l'
[3] = 'l'
[4] = 'o'
[5] = 'w'
[6] = 'o'
[7] = 'r'
[8] = 'l'
[9] = 'd'
[10] = '1'
[11] = '2'
[12] = '3'
[13] = '4'
[14] = '5'
[15] = '6'
[16] = '7'
[17] = '8'
[18] = '1'
[19] = '2'
[20] = '3'
[21] = '4'
[22] = '5'
[23] = 'q'
}
The thing here is if you still convert any character from Byte[] then you can only save one character at any index.
Because for above characters it's hex value is more than one character and you can only save one character in Byte[].
I suggest to use NSArray to save each character's hex value in NSString format.

Hashing the device id into a 64 bit (or greater) then convert that into base-31 [iOS]

I am having trouble hashing my device's id into a 64 bit (or greater) representation and then converting that into a base-31 representation. Any one have any tips or guidance? I have been looking online and can't seem to find much.
Each base-31 digit should then be represented by the this list: 2 3 4 5 6 7 8 9 A B C D E F G H J K M N P Q R S T U V W X Y Z
What I've tried:
NSString *myID = [[[UIDevice currentDevice] identifierForVendor]UUIDString];
NSLog(#"Non Hash: %#", myID); //Logs the 36 character string
myID = [NSString stringWithFormat:#"%lu",(unsigned long)[myID hash]]; // Changed thanks to rokjarc
NSLog(#"Hash: %#", myID); //Logs same 36 character string
//Logs 36 character string
NSLog(#"UUIDString: %#", [[[UIDevice currentDevice] identifierForVendor] UUIDString]);
//Logs out a 10 character numeric value
NSLog(#"Hash: %lu", (unsigned long)[[[[UIDevice currentDevice] identifierForVendor] UUIDString] hash]);
//Logs out a 2 character numeric value
NSLog(#"LongLong: %lld", [[[[UIDevice currentDevice] identifierForVendor] UUIDString] longLongValue]);
[[[UIDevice currentDevice] identifierForVendor]UUIDString] returns a UUID which is comprised of 32 hex characters which is 128 bits. 12 base31 characters can only represent 63 bits. Thus the entire UUID can not be represented.
Best bet is to run the UUID through SHA (which seems to be what [myID hash] does) and convert 63 of the bits of that into 12 base31 characters.
The reason for the hash function (SHA) is to remove any pattern in the UUID, each bit in the result of SHA is equally likely to be a 1 or 0.
Notes:
31^12 = 7.87E17 and 2^64 = 1.84E19
thus a 64 bit number can not be represented in 12 base 31 characters. 63 bit can however.
Base32 is a lot simpler than base31 for values larger than 64 bits.
Here is a code sample that creates a string of base31 characters from a 64-bit integer:
uint64_t uid = 14467240737094581;
NSString *baseCharacters = #"23456789ABCDEFGHJKMNPQRSTUVWXYZ";
NSUInteger base = baseCharacters.length;
NSMutableString *baseString = [NSMutableString new];
while (baseString.length < 12) {
uint64_t remainder = uid % base;
uid /= base;
NSString *baseCharacter = [baseCharacters substringWithRange:NSMakeRange(remainder, 1)];
[baseString insertString:baseCharacter atIndex:0];
}
NSLog(#"baseString: %#", baseString);
NSLog output:
baseString: 2KP7MAR5CX86

Reverse bit operation in objective-c / c++

I have opposite question for
If i have:
typedef enum {
SUNDAY = (1 << 0),
MONDAY = (1 << 1),
TUESDAY = (1 << 2),
WEDNESDAY = (1 << 3),
THURSDAY = (1 << 4),
FRIDAY = (1 << 5),
SATURDAY = (1 << 6),
} PFDateDays;
And my input is 65 for example (SUNDAY,SATURDAY) there is a clever way for etract this values from enum?
Here is my method:
-(NSMutableArray*)selectFromMyEnum {
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
int myInput = 62;
NSArray *enumArray = #[#(SATURDAY),#(FRIDAY),#(THURSDAY),#(WEDNESDAY),#(TUESDAY),#(MONDAY),#(SUNDAY)];
for(NSNumber *numberInEnumArray in enumArray) {
if(myInput >= [numberInEnumArray integerValue]) {
[returnArray addObject:numberInEnumArray];
myInput -= [numberInEnumArray integerValue];
}
}
NSLog(#"%#",returnArray);
return returnArray;
}
And this is output:
(
64, //SATURDAY
1 //SUNDAY
)
So this is correct. But maybe there is method I don't know about that allow me to do this without this pointless assign enum to array etc..
Well the first thing that comes to my mind is this. Since your enum is nicely laid out for flagging you can do something like this:
Start with your highest enum value (SATURDAY) and use a bitwise and (&) to check if your value contains it. Then shift the comparison value right by 1 and repeat until your comparison value is zero.
PFDateDays comparison = SATURDAY;
//If your enum doesn't end at 1 like the above example,
//you could also use >= SUNDAY
while(((int)comparison) > 0) {
if((myVal & comparison) == comparison)
//Do what you want, this value is valid
comparison = comparison >> 1;
}

lua loops stuck after 15 numbers

My code is designed to read digits and turn them into Chinese pinyin:
function digitconverter (digit)
if digit == "0" then
cnumber = "ying2 "
elseif digit == "1" then
cnumber = "yi1 "
elseif digit == "2" then
cnumber = "er2 "
elseif digit == "3" then
cnumber = "san1 "
elseif digit == "4" then
cnumber = "si4 "
elseif digit == "5" then
cnumber = "wu3 "
elseif digit == "6" then
cnumber = "liu4 "
elseif digit == "7" then
cnumber = "qi1 "
elseif digit == "8" then
cnumber = "ba1 "
elseif digit == "9" then
cnumber = "jiu3 "
end
return cnumber
end
print("Enter a number to be converted:")
repeat
strnumber = io.read("*line")
number = tonumber(strnumber)
if number ~= nil then
continue = true
else
print("Invalid input. Please try again:")
continue = false
end
until continue == true
nlength = #strnumber
digits = {}
for d in string.gmatch(number, "%d") do
digits[#digits + 1] = d
end
convnumber = ""
for d=1,nlength do
convnumber = convnumber .. digitconverter(digits[d])
end
print(convnumber)
io.read()
If I enter over 15 digits, it gets stuck (for lack of a better term). It WILL convert every digit, but the 16th will be random and the 17th and on will repeat another random one. I've been over it and I can't figure out where it's getting hung up. Thoughts?
You're iterating through the digits of number, not strnumber. The problem is when you get to too many digits, the string representation is going to be in scientific notation:
strnumber = '1234567890123456789'
number = tonumber(strnumber)
print(number) --> 1.2345678901235e+018
Side note: Lua is based on hashtables, which gives you (barring hash collisions) constant time lookup. So your digit converter can be simply written as a map:
local digitmap = {
["0"] = "ying2 ",
["1"] = "yi1 ",
["2"] = "er2 ",
["3"] = "san1 ",
["4"] = "si4 ",
["5"] = "wu3 ",
["6"] = "liu4 ",
["7"] = "qi1 ",
["8"] = "ba1 ",
["9"] = "jiu3 ",
}
Also, building strings like this is very inefficient:
for d=1,nlength do
convnumber = convnumber .. digitconverter(digits[d])
end
You're generating tons of intermediate strings, which requires a lot of allocations and produces a lot of garbage. It's much faster to put all the values you need to concatenate into a table, then call table.concat. Another advantage is that you can specify a delimiter (right now, you're hard coding the delimiter into your string table).
Using those techniques, we can rewrite your code like this:
local digitmap = {
['0'] = 'ying2',
['1'] = 'yi1',
['2'] = 'er2',
['3'] = 'san1',
['4'] = 'si4',
['5'] = 'wu3',
['6'] = 'liu4',
['7'] = 'qi1',
['8'] = 'ba1',
['9'] = 'jiu3',
}
print('Enter a number to be converted:')
while true do
strnumber = io.read('*line')
if not strnumber:match('%D') then
break
end
print('Invalid input. Please try again:')
end
local digits = {}
for digit in string.gmatch(strnumber, '%d') do
digits[#digits + 1] = digitmap[digit]
end
print(table.concat(digits, ' '))
Probably, you want to scan strnumber instead of number in the following line of your code:
for d in string.gmatch(number, "%d") do
Your number variable contains a numerical value in double format with 15-16 decimal digits.

Resources