Get substring between two ASCII control characters - ios

Example Response:
_STX_<Response>
<Error>Cancelled</Error>
</Response>
_ETX_<AuditCharacter_not_XML>_EOT_
_VAR_ are actual ASCII Hex codes (reference)
_STX_ = 0x02 // start of heading
_ETX_ = 0x03 // end of text
_EOT_ = 0x04 // end of transmission
We are doing some integration with some 3rd party devices, one of them we have a socket that reads in a response from the device. We use CocoaAsyncSocket for this. So the data is available to us as NSData or NSString
EG:
NSData *strData = [data subdataWithRange:NSMakeRange(0, [data length])];
NSString *msg = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
What i am trying to do is get the XML between the ASCII control characters.
One way that works is to do the following (Knowing that NSString is a UTF16)
NSRange rSub = NSMakeRange(1, [msg length] - 5);
NSString *sub = [msg substringWithRange:rSub];
This correctly returns the XML but this is very limited, what happens when the AuditCharacter is more than 1 byte/char. We should be getting the string between the two control STX and ETX characters.
We have tried the following
unichar STX = 0x02; // \u0002 Start of Text
unichar ETX = 0x03; // \u0003 End of Text
unichar EOT = 0x04; // \u0004 End of transmission
unichar ACK = 0x06; // \u0006 ACK
unichar NAK = 0x15; // \u0015 NAK
NSScanner *scanner = [NSScanner scannerWithString:msg];
// Tried as NSString
NSCharacterSet *seperator = [NSCharacterSet characterSetWithCharactersInString:[NSString stringWithFormat: #"<%c>", ETX]]
// Tried as NSData
NSCharacterSet *seperator = [NSCharacterSet characterSetWithBitmapRepresentation:[[NSData alloc] initWithBytes:&ETX length:2]]; // tried length as 1 and 2
That always seems to just return the whole string.
We then tried using a range
NSRange r1 = [msg rangeOfString:[NSString stringWithFormat: #"<%c>", STX]];
NSRange r2 = [msg rangeOfString:[NSString stringWithFormat: #"<%c>", ETX]];
But both ranges always return a length of zero.
I know this has to do with the fact that were trying to split/locate the control characters in the string but i am not sure what the correct why to do this would be.
Any help would be appreciated.

You're searching for the string <_STX_> with angle brackets, but your actual string doesn't have angle brackets there. Just remove the angle brackets.

Related

NSString stringWithCString not showing special characters?

I'm using
[NSString stringWithFormat:#"%C",(unichar)decimalValueX];
but I have to call it thousands of times and its simply too slow.
As an alternative I tried this:
sprintf (cString, "%C", (unichar)decimalValueX);
[NSString stringWithCString:cString encoding:NSUTF16StringEncoding];
but no characters are correctly transalted.
If I try UTF8 instead of 16:
sprintf (cString, "%C", (unichar)decimalValueX);
[NSString stringWithCString:cString encoding:NSUTF8StringEncoding];
I get alphanumeric, but I don't get foreign characters or other special characters.
Can anyone explain whats going on? Or how to make stringWithFormat faster?
Thanks!
It seems that the %C format does not work with sprintf and related functions and non-ASCII characters. But there is a simpler method:
stringWithCharacters:length:
creates an NSString directly from a unichar array (UTF-16 code points).
For a single unichar this would be just
NSString *string = [NSString stringWithCharacters:&decimalValueX length:1];
Example:
unichar decimalValueX = 8364; // The Euro character
NSString *string = [NSString stringWithCharacters:&decimalValueX length:1];
NSLog(#"%#", string); // €
Example for multiple UTF-16 code points:
unichar utf16[] = { 945, 946, 947 };
NSString *string3 = [NSString stringWithCharacters:utf16 length:3];
NSLog(#"%#", string3); // αβγ
For characters outside of the "basic multilingual plane" (i.e.
characters > U+FFFF) you would have to use 2 UTF-16 code points
per character (surrogate pair).
Or use a different API like
uint32_t utf32[] = { 128123, 128121 };
NSString *string4 = [[NSString alloc] initWithBytes:utf32 length:2*4 encoding:NSUTF32LittleEndianStringEncoding];
NSLog(#"%#", string4); // 👻👹

How to display the emoji and special characters in UIlabel and UItextviews?

I am trying to display a string in all sorts of items such as UIlabel,UItextview,Uitextfield etc.....I am trying to do like this in a manner like this
NSData *data1 = [title dataUsingEncoding:NSUTF8StringEncoding];
NSString *goodValue = [[NSString alloc] initWithData:data1 encoding:NSNonLossyASCIIStringEncoding];
label.text=goodvalue;
this is working sometimes for me ,but some times it returns null for the string like this "Youtube\ud83d\ude27\ud83d\ude2e\ud83d\ude2f\ud83d".Can anybody guide me on this?
Emoji characters are in unicode plane 1 and thus require more than 16 bits to represent a code point. Thus two UTF8 representations or one UTF32 representation. Unicode is actually a 21-bit system and for plane 0 characters (basically everything except emoji) 16 bits is sufficient and we get by using 16 bits. Emoji need more than 16 bits.
"Youtube\ud83d\ude27\ud83d\ude2e\ud83d\ude2f\ud83d". is invalid, it is part of a utf16 unicode escaped string, the last \ud83d is 1/2 of an emoji character.
Also, inorder to create a literal string with the escape character "\" the escape character must be escaped: "\\".
NSString *emojiEscaped = #"Youtube\\ud83d\\ude27\\ud83d\\ude2e\\ud83d\\ude2f";
NSData *emojiData = [emojiEscaped dataUsingEncoding:NSUTF8StringEncoding];
NSString *emojiString = [[NSString alloc] initWithData:emojiData encoding:NSNonLossyASCIIStringEncoding];
NSLog(#"emojiString: %#", emojiString);
NSLog output:
emojiString: Youtube😧😮😯
The emoji string can also be expressed in utf32:
NSString *string = #"\U0001f627\U0001f62e\U0001f62f";
NSLog(#"string: %#", string);
NSLog output:
string1: 😧😮😯
NSString *str = #"Happy to help you \U0001F431";
NSData *data = [str dataUsingEncoding:NSNonLossyASCIIStringEncoding];
NSString *valueUnicode = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSData *dataa = [valueUnicode dataUsingEncoding:NSUTF8StringEncoding];
NSString *valueEmoj = [[NSString alloc] initWithData:dataa encoding:NSNonLossyASCIIStringEncoding];
_lbl.text = valueEmoj;

Getting more than char from string variable

I have an NSString *fileName
This will contain a variable number from 1 to 3 digits. I want to extract all of the digits
I can get the first digit using
//create text for appliance identifier
char obsNumber = [fileName characterAtIndex:3];//get 4 character
NSLog(#"Obs number %c",obsNumber);
//Text label
[cell.titleLabel setText:[NSString stringWithFormat:#"Item No: %c",obsNumber]];
NSLog(#"Label for observation = %#",cell.titleLabel.text);
However if the string contains the number for example 78, or 204 I want to catch all two or three digits.
I tried this
//create text for appliance identifier
char obsNumber1 = [fileName characterAtIndex:3];//get 4 character
char obsNumber2 = [fileName characterAtIndex:4];//get 5 character
char obsNumber3 = [fileName characterAtIndex:5];//get 6 character
NSLog(#"Obs number %c,%c,%c",obsNumber1,obsNumber2,obsNumber3);
//Text label
[cell.titleLabel setText:[NSString stringWithFormat:#"Item No: %c,%c,%c",obsNumber1,obsNumber2,obsNumber3]];
NSLog(#"Label for observation = %#",cell.titleLabel.text);
This gave me 18c 1ce etc
Would this work for you?
NSString *filename = #"obs127observation"; //An example variable with your format
This code could be tidier but you should get the idea:
NSString *filenameNumber = [[filename
stringByReplacingOccurrencesOfString:#"observation"
withString:#""]
stringByReplacingOccurrencesOfString:#"obs"
withString:#""];
you can trim other letters except the decimals.
NSString *onlyNumbers=[yourstring stringByTrimmingCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
As your comment says , It has predefined set of values, right. Then try like this
NSstring *str = [filename substringFromIndex:11];
// Convert the str to char[]
Then you should try with the NSScanner :
NSString *numberString;
NSScanner *scanner = [NSScanner scannerWithString:filename];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
// Throw away characters before the first number.
[scanner scanUpToCharactersFromSet:numbers intoString:NULL];
// Collect numbers.
[scanner scanCharactersFromSet:numbers intoString:&numberString];
// Result.
int number = [numberString integerValue];
// you can play around with the set of number
Your approach of separating one character at a time and then combining them back into a string is an awkward, overly complex way of going about this. Kumar's suggestion of using NSScanner is a good option if you have a number in the middle of a string.
However, you make it sound like your string will always contain a number and only a number. Is that true? Or will there be characters you need to ignore?
You need to define the problem clearly and completely before you can select the best solution.
It might be as simple as using the NSString method substringWithRange.

NSString with Japanese Chars

In my application i have NSString that get String from the web:
高瀬 - 虎柄の毘沙門天
Now i want to copy this string to a local NSString in my Object so i wrote:
self.metaDataString = [NSString stringWithString:tempMetaDataString];
And now in metaDataString i have :
é«ç¬ - èæã®æ¯æ²é天
What can make this problem?
i tried this too:
self.metaDataString = [NSString stringWithUTF8String:[tempMetaDataString UTF8String]];
How i get tempMetaDataString:
NSMutableString *tempMetaDataString = [NSMutableString stringWithCapacity:0];
//This line i loop over the bytes array size
[tempMetaDataString appendFormat:#"%c", bytes[i]];
And this is the bytes array:
UInt8 bytes[kAQBufSize];
length = CFReadStreamRead(stream, bytes, kAQBufSize);
This line cannot work for multi-byte characters:
[tempMetaDataString appendFormat:#"%c", bytes[i]];
If you have a multi-byte character, this is going to split it up into individual ASCII characters (as you're seeing).
It's unclear from this code what bytes really is. Is the string of a fixed length, or is the string NULL terminated? If it's of a fixed length, then you want (assuming this is UTF8):
self.metaDataString = [[NSString alloc] initWithBytes:bytes
length:kAQBufSize
encoding:NSUTF8StringEncoding];
If this is a NULL terminated UTF8 string:
self.metaDataString = [NSString stringWithUTF8String:bytes];
If some other encoding (for example NSJapaneseEUCStringEncoding or NSShiftJISStringEncoding):
self.metaDataString = [NSString stringWithCString:bytes encoding:theEncoding];

NSArray element to NSString

I have application where I receive from socket message like: "\r\nIDLE|03/17/2013 19:48\n". I convert this message into UTF8 string with code:
NSString* newStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
then I try to separate command and time from this string:
NSArray *nums = [command componentsSeparatedByString:[NSString stringWithFormat:#"%c", (char)13]];
NSLog(#"First separate = %#", nums);
if ([nums count] == 3)
{
NSArray *nums1 = [[nums objectAtIndex:1] componentsSeparatedByString:#"|"];
NSLog(#"second separate = %#", nums1);
if ([nums1 count] == 2)
{
NSString* strState = [(NSString *)[nums1 objectAtIndex:0] description];
NSLog(#"State = %#", strState);
...
}
}
in the log I see next:
First separate = (
"IDLE|03/17/2013 19:48",
"\n"
second separate = (
"IDLE",
"03/17/2013 19:48"
State = I
After second separating in the 0 elements I have text IDLE, but when I try to get this text I strState variable, I see only first character of this text.
Can anybody help me get full command of this element?
Thank you.
UPDATE1
As I say previously I get from socket message like:"\r\nIDLE|03/17/2013 19:48\n"
I'm sure that the server send me this message.
in the Socket read callback I'm use next code for reading this message:
int result = CFReadStreamRead(_inputStream, (UInt8*)[data mutableBytes], length);
NSString* newStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Here app read 50 bytes and this is right for this message? you can see my debugger at this point in the next picture:
but in the newStr member I see only \r.
then I send try separate this message with code I wrote above.
When I try separate message logger show me all message instead of \r:
Thank you
Have you considered using sscanf()?
char command[COMMAND_SIZE_LIMIT];
char date[DATE_SIZE_LIMIT];
char time[TIME_SIZE_LIMIT];
sscanf (input, "\r\n%[^|]%*[|]%s%s\n", command, date, time);
(Note: Above is example code; you've got a security issue if the scanned string has oversized command or datetime substrings.)
# test
ebg#ebg$ ./foo
Input: '
IDLE|03/17/2013 19:48
'
Command: 'IDLE'
Date: '03/17/2013'
Time: '19:48'
It is easy to convert NSString <==> C string.
There is a fairly straightforward way to accomplish what you want using the -[NSString stringByTrimmingCharactersInSet:] method. Passing the whitespace and newline character set allows you to trim the leading and trailing whitespace and newlines from your string, and then you only need to do a single call to componentsSeparatedByString:.
NSString *raw = #"\r\nIDLE|03/17/2013 19:48\n";
NSString *trimmedString = [raw stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *components = [trimmedString componentsSeparatedByString:#"|"];
NSString *command = components[0];
NSString *time = components[1];
NSLog(#"command = %#, time = %#",command,time);
This code yields the following output:
command = IDLE, time = 03/17/2013 19:48

Resources