How to create string buffer to iterate over it and convert value of type 'String.CharacterView.Index' to expected argument type 'Int'? - objective-c

ObjC code:
#pragma mark - bookNameFromString
+(NSString *) bookNameFromString:(NSString *)string{
NSMutableArray *newLineArray = [[NSMutableArray alloc]init];
NSUInteger length = [string length];
unichar buffer[length+1];
[string getCharacters:buffer range:NSMakeRange(0, length)];
NSInteger a = 0;
do {
a = a+ 1;
char current = buffer[a];
if (current == '\n') {
[newLineArray addObject:[NSNumber numberWithInteger:a]];
break;
}
} while (a <= length);
NSString *bookName = nil;
if (newLineArray.count > 0 && newLineArray[0] != 0) {
bookName = [string substringToIndex:[newLineArray[0]integerValue]];
}
return bookName;
}
In Swift:
While converting to swift
How to create string buffer as done in objC.
While appending value to array, there is an error: Cannot convert value of type 'String.CharacterView.Index' to expected argument type 'Int'
// MARK: - bookNameFromString
func bookNameFromString(string:String) ->String {
let toFind:Character = "\n"
var newLineArray:[Int] = []
let lengthOfString = string.characters.count
var a = 0
repeat{
a = a + 1
if let index = string.characters.indexOf(toFind) {
newLineArray.append(index) */ERROR: Cannot convert value of type 'String.CharacterView.Index' to expected argument type 'Int'/*
break
}
}while a < lengthOfString
print(newLineArray)
var bookName:String
if newLineArray.count > 0 && newLineArray[0] != 0{
bookName = string.substringToIndex(string.startIndex.advancedBy(newLineArray[0]))
}
return bookName
}

This is an attempt of an approach without buffers and checking single characters
func bookNameFromString(string : String) -> String?
{
// separate string by linefeed character
let array = string.componentsSeparatedByString("\n")
// if string is empty or there is none or one linefeed - exit
guard array.count > 1 else { return nil }
// define a startindex which is 1 if the string starts with linefeed
let startIndex = array[0].isEmpty ? 1 : 0
// if there is no linefeed left - exit
guard array.count > startIndex + 1 else { return nil }
return startIndex == 1 ? "\n" + array[startIndex] : array[startIndex]
}
bookNameFromString("") // -> nil
bookNameFromString("\n") // -> nil
bookNameFromString("\n\n") // -> \n
bookNameFromString("Hello") // -> nil
bookNameFromString("\nHello") // -> nil
bookNameFromString("Hello\n") // -> Hello
bookNameFromString("Hello\nWorld") // -> Hello
bookNameFromString("\nHello\n") // -> \nHello
bookNameFromString("\nHello\nWorld") // -> \nHello

Related

How to unescape backslashes on macOS?

Localized.strings files may contain escaped chars like \n and \".
How do I efficiently unescape them?
I know I could write my own function that looks for a \ and removes it and then keeps searching at the second-next character (so that I don't turn \\ into nothing), but that won't handle special escape methods such as an octal character numbers (e.g. \012 for a LF) and possibly other forms.
I'd think that NSString would offer a function for that but I can't find any.
Actually, this appears to be a duplicate of NSString strip regular \ escape characters how?, but that question has a lot of bad answers and not a single correct answer. And the user is not active any more, meaning no one will ever accept a correct answer there. How shall that be handled on SO?
Here's a self-written ObjC version that works for most cases. It defines an unescaped method for NSString.
#import <Cocoa/Cocoa.h>
#interface NSString (BackslashUnescaping)
- (NSString*) unescaped;
#end
#implementation NSString (BackslashUnescaping)
- (NSString*) unescaped
{
NSString *text = self;
NSInteger charIndex = 0;
while (true) {
NSInteger textLen = text.length;
if (charIndex >= textLen) {
break;
}
NSRange remainingRange = NSMakeRange (charIndex, textLen-charIndex);
NSRange charRange = [text rangeOfString:#"\\"options:0 range:remainingRange];
if (charRange.length == 0) {
// no more backslashes -> done
break;
}
charIndex = charRange.location + 1;
if (charIndex >= textLen) {
// reached end of string -> exit loop
break;
}
// check char following the backslash
unichar nextChar = [text characterAtIndex:charIndex];
unichar replacementChar;
NSInteger skipLen = 1;
if (nextChar >= 'a' && nextChar <= 'z') {
if (nextChar == 'n') {
replacementChar = '\n'; // LF
} else if (nextChar == 'r') {
replacementChar = '\r'; // CR
} else if (nextChar == 't') {
replacementChar = '\t'; // TAB
} else if (nextChar == 'x') {
// A hex char code
const NSInteger xtraLen = 2;
if (charIndex+xtraLen >= textLen) break;
// Note: Does not make sure that both chars are valid hex chars
NSString *code = [text substringWithRange:NSMakeRange(charIndex+1, 2)];
char ch = strtol(code.UTF8String, NULL, 16);
replacementChar = ch;
skipLen += xtraLen;
} else if (nextChar == 'u') {
// A unicode char code
const NSInteger xtraLen = 4;
if (charIndex+xtraLen >= textLen) break;
// Note: Does not make sure that all four chars are valid hex chars
NSString *code = [text substringWithRange:NSMakeRange(charIndex+1, 4)];
unichar ch = strtol(code.UTF8String, NULL, 16);
replacementChar = ch;
skipLen += xtraLen;
} else {
// an unknown escape code - this should be fixed
NSAssert(false, #"There's a case missing for escaping \\%c", nextChar);
}
} else if (nextChar >= '0' && nextChar <= '9') {
unichar nextChar2 = 0;
if (charIndex > textLen) { // get the second octal char
nextChar2 = [text characterAtIndex:charIndex+1];
}
if (nextChar == '0' && (nextChar2 < '0' || nextChar2 > '9')) {
// A short NUL (\0) char
replacementChar = 0;
} else {
// An octal char code
const NSInteger xtraLen = 2;
if (charIndex+xtraLen >= textLen) break;
// Note: Does not make sure that the last char is a valid octal char
NSString *code = [text substringWithRange:NSMakeRange(charIndex, 3)];
char ch = strtol(code.UTF8String, NULL, 8); // https://stackoverflow.com/a/12820646/43615
replacementChar = ch;
skipLen += xtraLen;
}
} else {
// Handle all generic escapes, like for \\ and \"
replacementChar = nextChar;
}
#if 0 // Use string concatenation
charIndex += skipLen-1;
NSString *head = [text substringToIndex:charRange.location];
NSString *tail = [text substringFromIndex:charIndex+1];
text = [NSString stringWithFormat:#"%#%C%#", head, replacementChar, tail];
#else // Use a mutable string
if (text == self) {
text = text.mutableCopy;
}
NSRange replacedRange = NSMakeRange(charRange.location, skipLen+1);
NSString *replacement = [NSString stringWithCharacters:&replacementChar length:1];
[(NSMutableString*)text replaceCharactersInRange:replacedRange withString:replacement];
charIndex += 1;
#endif
}
return text;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSArray *testValues = #[
#"CR:\\rLF:\\n",
#"\\\"quoted\\\"",
#"Backslash: \\\\",
#"Octal x (\170):\\170",
#"Hex x (\x78):\\x78",
#"Unicode Ф (\u0424):\\u0424",
#"NUL char:\\0.",
#"Bad Hex:\\x7x", // this is not detected being invalid
#"Bad Hex:\\x7",
#"Incomplete :\\13"
];
for (NSString *s in testValues) {
NSString *s2 = [NSString stringWithFormat:#"Escaped: %#\nUnescaped: %#", s, s.unescaped];
printf("\n%s\n", s2.UTF8String);
}
}
return 0;
}

how Hexadecimal string to Bytes

how hexadecimal string to Bytes and Bytes to hexadecimal string?
I have oc code but I can not to write in swift
can u help me ?
thanks so much
+ (NSData *)convertHexToDataBytes:(NSString *)hexStr {
NSMutableData *dataBytes = [NSMutableData data];
int idx;
for (idx = 0; idx + 2 <= hexStr.length; idx += 2) {
NSRange range = NSMakeRange(idx, 2);
NSString *singleHexStr = [hexStr substringWithRange:range];
NSScanner *scanner = [NSScanner scannerWithString:singleHexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[dataBytes appendBytes:&intValue length:1];
}
return dataBytes;
}
+ (NSString *)convertDataBytesToHex:(NSData *)dataBytes {
if (!dataBytes || [dataBytes length] == 0) {
return #"";
}
NSMutableString *hexStr = [[NSMutableString alloc] initWithCapacity:[dataBytes length]];
[dataBytes enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char *)bytes;
for (NSInteger i = 0; i < byteRange.length; i ++) {
NSString *singleHexStr = [NSString stringWithFormat:#"%x", (dataBytes[i]) & 0xff];
if ([singleHexStr length] == 2) {
[hexStr appendString:singleHexStr];
} else {
[hexStr appendFormat:#"0%#", singleHexStr];
}
}
}];
return hexStr;
}
I write in swift like this
class func convertHex(toDataBytes hexStr: String?) -> Data? {
var dataBytes = Data()
var idx: Int
idx = 0
while idx + 2 <= (hexStr?.count ?? 0) {
let range = NSRange(location: idx, length: 2)
let singleHexStr = (hexStr as NSString?)?.substring(with: range)
let scanner = Scanner(string: singleHexStr ?? "")
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
dataBytes.append(&intValue, count: 1)
idx += 2
}
return dataBytes
}
its error says:Cannot pass immutable value as inout argument: function call returns immutable value how to fix it?
To answer your immediate question: UInt32(intValue) creates a new (constant) value whose address cannot be taken with &. So
var intValue: UInt
scanner.scanHexInt32(&UInt32(intValue))
should be
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
And
dataBytes.append(&intValue, count: 1)
does not compile because &intValue is a pointer to an integer, not to an UInt8. Here you can do
dataBytes.append(UInt8(intValue))
because the value is known to fit in a single byte.
Having said that, all the conversions from String to NSString are not needed. A more “Swifty” translation of that Objective-C code to Swift would be
func convertHex(toDataBytes hexStr: String) -> Data {
var dataBytes = Data()
var startPos = hexStr.startIndex
while let endPos = hexStr.index(startPos, offsetBy: 2, limitedBy: hexStr.endIndex) {
let singleHexStr = hexStr[startPos..<endPos]
let scanner = Scanner(string: String(singleHexStr))
var intValue: UInt32 = 0
scanner.scanHexInt32(&intValue)
dataBytes.append(UInt8(intValue))
startPos = endPos
}
return dataBytes
}
For an alternative approach (which includes error checking) see for example
hex/binary string conversion in Swift

Type checking string value like "string" & "integer" & "boolean"·

I have strings containing names of types. Therefore it is not instances on the types, I only have the string value describing the type and an input text in string.
NSString *text = #"1234";
NSString *type = #"integer";
NSString *text = #"hello there";
NSString *type = #"string";
NSString *text = #"true";
NSString *type = #"bool";
How would you check if it is a valid type from the tekst.
Would NSRegularExpression be the right way or how would you do it?
I have the following lines of code.
- (NSInteger)getStringType:(NSString *)value :(BOOL)a {
if ([value isEqualToString:#"true"] || [value isEqualToString:#"false"]) {
return 2;
}
else {
// a: Whether to accept 0
NSRange range;
NSString *expression = #"^[1-9][0-9]*$";
range = [value rangeOfString:expression options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
return 1;
} else {
if (a == YES) {
if (value.length == 1 && [value isEqualToString:#"0"]) {
return 1;
} else {
return 0;
}
}
else {
return 0;
}
}
}
}
If the string (value) is boolean, it should return 2. If it's an integer, it should return 1. Otherwise, it will return 0. That is, if it's a string, whether it's empty or not, you'll get 0. If you want to include '0' as a number, set 'a' to YES. This function is tested under the OSX platform.
You can use NSScanner, an algorithm in outline :
Create an instance of NSScanner for your text string
Based on the value of your type string call the appropriate method of NSScanner, e.g. scanInteger: for integers and scanString:intoString: for booleans (hint: scan for the boolean literals)
If the scanning method returns YES then check the isAtEnd method to make sure there is no garbage after the scanned value
HTH

Definition error while using instance of class that is in an if loop

----I have two instances of NSString, and one of them is defined within a while loop, but the other one is after that. Xcode seems to think that since this first instance (we'll call string1) is in a while loop, it will not be defined. However, for the program to proceed out of the while loop IT WILL ALWAYS DEFINE STRING1. An NSString is in another while loop thats the same thing.
----Outside of both while loops, at the end, in the code I have a method of NSString done to both of them (isEqualtoString), but Xcode tells me that string1 and string two are not defined. The program should work, but the compiler stops me. Is there anything I can change to make string1 and string2 appear defined in Xcode's eyes.
----I'm using this for the registration page, and I need these in while loops because they need to cycle until the user enters in through the console a username that fits my requirements.
EDIT: Added in actual code.
int numb1, numb2;
char usercheck1[60];
char usercheck2[60];
//Registration
numb2 = 1;
while (numb2 == 1){
numb1 = 1;
while (numb1 == 1){
numb1 = 0;
NSLog(#"Username:");
fgets(usercheck1, sizeof usercheck1, stdin);
int c2;
while((c2 = getchar()) != '\n' && c2 != EOF);
if (usercheck1 [sizeof (usercheck1)-1] == '\n'){ // In case that the input string has 12 characters plus '\n'
usercheck1 [sizeof (usercheck1)-1] = '\0';} // Plus '\0', the '\n' isn't added and the if condition is false.
NSString* string1 = [NSString stringWithUTF8String: usercheck1];
//Makes sure string contains no spaces and string length is correct size.
if ([string1 length] > 12){
NSLog (#"Username must be 12 characters or less!");
numb1 = 1;}
if ([string1 length] < 5){
NSLog (#"Username must be 4 characters or more!");
numb1 = 1;}
if ([string1 rangeOfString:#" " ].location != NSNotFound){
NSLog(#"Username cannot contain spaces!");
numb1 = 1;}
}
numb1 = 1;
while (numb1 == 1){
numb1 = 0;
NSLog(#"Confirm Username:");
fgets(usercheck2, sizeof usercheck2, stdin);
int c2;
while((c2 = getchar()) != '\n' && c2 != EOF);
if (usercheck2 [sizeof (usercheck2)-1] == '\n'){ // In case that the input string has 12 characters plus '\n'
usercheck2 [sizeof (usercheck2)-1] = '\0';} // Plus '\0', the '\n' isn't added and the if condition is false.
NSString* string2 = [NSString stringWithUTF8String: usercheck2];
//Makes sure string contains no spaces and string length is correct size.
if ([string2 length] > 12){
NSLog (#"Username must be 12 characters or less!");
numb1 = 1;}
if ([string2 length] < 5){
NSLog (#"Username must be 4 characters or more!");
numb1 = 1;}
if ([string2 rangeOfString:#" " ].location != NSNotFound){
NSLog(#"Username cannot contain spaces!");
numb1 = 1;}
}
if ([string2 isEqualToString: string1] == YES){
NSLog(#"Usernames confirmed! Username:%s", string2);
numb2 = 0;}
else {NSLog(#"Usernames do not match. Try again");
numb2 = 1;}
}
}
As you can see, it would work if it actually compiled and ran, but the compiler just doesn't like me using string2 in the if statement for isEqualToString. It gives me the error :
"Use of undeclared identifier 'string2'"
Also, move that statement and the else statment outside the two sub-while statements, it gives me that error for BOTH string1 and string2.
XCode version is 4.6.3, I'm programming for the Mac OS X on 10.8.4
You can't access variables outside of the scope in which they are declared. Since string1 and string2 are declared within the two while blocks, you can't use them outside of the while blocks.
There are many things that could be improved in this code. Try something like this:
NSString *username1;
NSString *username2;
while (1) {
while (1) {
NSLog(#"Username:");
char usercheck[60];
fgets(usercheck, sizeof usercheck1, stdin);
int c2;
while ((c2 = getchar()) != '\n' && c2 != EOF);
if (usercheck [sizeof (usercheck) - 1] == '\n') { // In case that the input string has 12 characters plus '\n'
usercheck[sizeof (usercheck)-1] = '\0';
} // Plus '\0', the '\n' isn't added and the if condition is false.
NSString *string1 = [NSString stringWithUTF8String:usercheck];
// Makes sure string contains no spaces and string length is correct size.
if ([string1 length] > 12) {
NSLog(#"Username must be 12 characters or less!");
} else if ([string1 length] < 5) {
NSLog(#"Username must be 4 characters or more!");
} else if ([string1 rangeOfString:#" "].location != NSNotFound) {
NSLog(#"Username cannot contain spaces!");
} else {
username1 = string1;
break; // username is good
}
}
while (1) {
NSLog(#"Confirm Username:");
char usercheck[60];
fgets(usercheck, sizeof usercheck, stdin);
int c2;
while ((c2 = getchar()) != '\n' && c2 != EOF);
if (usercheck[sizeof (usercheck) - 1] == '\n') { // In case that the input string has 12 characters plus '\n'
usercheck[sizeof (usercheck) - 1] = '\0';
} // Plus '\0', the '\n' isn't added and the if condition is false.
NSString *string2 = [NSString stringWithUTF8String:usercheck];
//Makes sure string contains no spaces and string length is correct size.
if ([string2 length] > 12) {
NSLog (#"Username must be 12 characters or less!");
} else if ([string2 length] < 5) {
NSLog (#"Username must be 4 characters or more!");
} else if ([string2 rangeOfString:#" "].location != NSNotFound) {
NSLog(#"Username cannot contain spaces!");
} else {
username2 = string2;
break;
}
}
if ([username1 isEqualToString:username2]) {
NSLog(#"Usernames confirmed! Username:%#", username1);
break;
} else {
NSLog(#"Usernames do not match. Try again");
}
}

Calculate LRC in Objective c

I want to calculate the LRC of a message that I send via Bluetooth. Here is for example a message :
(The message structure is STX MESSAGE FS EXT LRC)
02 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR 1C 03 60
STX = 02
MESSAGE = 1212004123422826E0B8C0F000F0A00182620000THYRON SYSTEMS WATFORD UKR
FS = 1C
EXT = 03
LRC = 60
What I have to do is calculate the LRC by performing a modulo 2 binary sum of every character in the communication message excluding the STX character but including the EXT characterr.
Before to calculate the LRC, I have to convert this NSString in HexaString :
31323132 30303431 32333432 32383236 45304238 43304630 30304630 41303031 38323632 30303030 54485952 4f4e2053 59535445 4d532057 4154464f 52442055 4b521c03
Method used :
- (NSString *) stringToHex:(NSString *)str
{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
[hexString appendFormat:#"%02x", chars[i]];
}
free(chars);
return [hexString autorelease];
}
And then I have to convert it in Byte Array.
Method used :
- (NSData*) hexToBytes:(NSString *) hexaStr {
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= hexaStr.length; idx+=2) {
NSRange range = NSMakeRange(idx, 2);
NSString * hexStrTmp = [hexaStr substringWithRange:range];
NSScanner* scanner = [NSScanner scannerWithString:hexStrTmp];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
And then I try to do calculate my LRC, that should be 60, with the following :
- (void) calculateLRC:(NSString *) text {
NSData * data = [self hexToBytes:text];
NSUInteger size = [data length] / sizeof(const char);
const char * array = (const char*) [data bytes];
char checksum = 0;
for( uint32_t i = 0 ; i < size; i++) {
checksum += * array++;
}
NSLog(#"Checksum = %c", checksum);
self.LRC_Check = checksum;
}
The problem is that "checksum" has not the value "60" in it. Can someone help me with that please ?
Thanx in advance !
I have the answer !
In the method - (void) calculateLRC:(NSString *) text I have to replace :
checksum += * array++;
with :
checksum ^= * array++;
I thougt the Modulo character was "%" in Objective C...
I needed to do this in swift
this seems to work . .need to do some rigorous testing though..
var str = computeLRC(hexString:"373203")
print(str)
// returns 06
func computeLRC (hexString: String ) -> String {
var checksum : UInt16 = 0
var my = ""
for i in stride(from: 0, to: hexString.count, by: 2) {
let indexStartOfText = hexString.index( hexString.startIndex, offsetBy: i)
let indexEndOfText = hexString.index( indexStartOfText, offsetBy: 2)
let substring3 = hexString[indexStartOfText..<indexEndOfText]
let intResult = Int(String(substring3) , radix: 16)
guard let myUnicodeScalar = UnicodeScalar(intResult!) else {
return ""
}
// convert UnicodeScalar to Character
let myCharacter = Character(myUnicodeScalar)
my += String(myCharacter)
}
for myChar in my {
var byte: UInt16 = Array(String(myChar).utf16)[0]
checksum ^= byte
}
return String(format:"%02X", checksum)
}