How to grab values from unformatted string in ios objective-c? - ios

I want to pick all the measurement values from below string and need to store into one array. I am getting this type of string from machine whoes name is "Kane". when I connected with this machine using bluetooth at that time I am getting this type of string. I am able to print this string into console. but I am not able to retrive values from this string and I want to store into an array. Can anyone please help me out. Thanks
i want to store values of [serial no,Log No,DATE,TIME,CO2,CO,CO2,CO2,CO,CO/CO2,T1,T2,DELTA] in one single array, like: [12345,0002,23/02/18,17:43:16, -0.00,0,0.00,-0.00,0,0.000,-N\F-,-N\F-,-N\F-].
here is the string which i actually get from machine and print into textview:
KANE458 SW19392 V1.13
SERIAL No. 12345
LOG No. 0002
DATE 23/02/18
TIME 17:43:16
------------------------
NEXT CAL 11/12/18
------------------------
COMMISSION TEST
------------------------
ANALYSER ZERO
-------------
CO2 % -0.00
CO ppm 0
FLUE INTEGRITY
--------------
CO2 % 0.00
MAX GAS FLOW
------------
CO2 % -0.00
CO ppm 0
CO/CO2 0.0000
MIN GAS FLOW
------------
CO2 % -0.00
CO ppm 0
CO/CO2 0.0000
FLOW & RETURN
-------------
T1 (null)C -N\F-
T2 (null)C -N\F-
DELTA (null)C -N\F-
I want an array containing everything after the last space character from every line

Edited Answer:
OK - so you want the "last word" of each line.
But ---- we assume you want to ignore lines that don't have a "value" at the end. So:
split the string into an array of "lines"
create a list of lines to ignore
loop through the array of lines
IF the line is in the ignore list, ignore it
else, get the last word and add it to our "last words" array
So...
NSString *searchedString = #"KANE458 SW19392 V1.13\n\nSERIAL No. 12345\n\nLOG No. 0002\n\nDATE 23/02/18 \nTIME 17:43:16\n\n------------------------\nNEXT CAL 11/12/18\n------------------------\n\nCOMMISSION TEST\n------------------------\n\nANALYSER ZERO\n-------------\nCO2 % -0.00\n\nCO ppm 0\n\nFLUE INTEGRITY\n--------------\n\nCO2 % 0.00\n\nMAX GAS FLOW\n------------\nCO2 % -0.00\nCO ppm 0\nCO/CO2 0.0000\n\nMIN GAS FLOW\n------------\nCO2 % -0.00\n\nCO ppm 0\n\nCO/CO2 0.0000\n\nFLOW & RETURN\n-------------\nT1 (null)C -N\F-\n\nT2 (null)C -N\F-\n\nDELTA (null)C -N\F-\n";
// lines to ignore, because they have no "values"
NSString *ignoreLines = #"COMMISSION TEST,ANALYSER ZERO,FLUE INTEGRITY,MAX GAS FLOW,MIN GAS FLOW,FLOW & RETURN";
// initialize an array for the last "word" from each line
NSMutableArray *arrayOfLastWords = [NSMutableArray array];
// split string into an array of "lines"
NSArray *arrayOfLines = [searchedString componentsSeparatedByString:#"\n"];
// for each "line"
for (NSString *s in arrayOfLines) {
// see if this line is listed as one of the lines to ignore
NSRange ignoreRange = [ignoreLines rangeOfString:s];
// if not found, then we want to get the last "word"
if (ignoreRange.location == NSNotFound) {
// find last space character
NSRange range = [s rangeOfString:#" " options:NSBackwardsSearch];
// if the line has a space
if (range.location != NSNotFound) {
// gett the last "word" - everything after the last space
NSString *result = [s substringFromIndex:range.location+1];
// append it to our array of last words
[arrayOfLastWords addObject:result];
}
}
}
NSLog(#"\n%#", arrayOfLastWords);
Gives a resulting array of:
(
"V1.13",
12345,
0002,
"",
"17:43:16",
"11/12/18",
"-0.00",
0,
"0.00",
"-0.00",
0,
"0.0000",
"-0.00",
0,
"0.0000",
"-NF-",
"-NF-",
"-NF-"
)
If you don't want the "V1.13" from the first line, just skip processing the first line.
If you don't know that the string will be returned with newLine separators, or if you don't know what strings will be returned that you need to ignore, then you need to write some additional code to split the string on various separators, and come up with criteria of what constitutes a "line with a value".
Original Answer:
You could do this with a "brute force" approach:
Split the string into an array of "lines"
loop through the lines
check the first "word" in each line
if it matches "CO2" or "T1", get the rest of the line (skipping spaces) and add it to an array
Or, you could use Regular Expressions. This is a partial approach:
NSString *searchedString = #"KANE458 SW19392 V1.13\n\nSERIAL No. 12345\n\nLOG No. 0002\n\nDATE 23/02/18 \nTIME 17:43:16\n\n------------------------\nNEXT CAL 11/12/18\n------------------------\n\nCOMMISSION TEST\n------------------------\n\nANALYSER ZERO\n-------------\nCO2 % -0.00\n\nCO ppm 0\n\nFLUE INTEGRITY\n--------------\n\nCO2 % 0.00\n\nMAX GAS FLOW\n------------\nCO2 % -0.00\nCO ppm 0\nCO/CO2 0.0000\n\nMIN GAS FLOW\n------------\nCO2 % -0.00\n\nCO ppm 0\n\nCO/CO2 0.0000\n\nFLOW & RETURN\n-------------\nT1 (null)C -N\F-\n\nT2 (null)C -N\F-\n\nDELTA (null)C -N\F-\n";
NSError *error = nil;
NSRange searchedRange = NSMakeRange(0, [searchedString length]);
// search for "CO2" at the start of a line, and capture everything to the end of the line
NSString *pattern = #"\\nCO2\\s*([^\\n\\r]*)";
NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern: pattern options:0 error:&error];
NSArray* matches = [regex matchesInString:searchedString options:0 range: searchedRange];
// for each found match, skip spaces and save the rest of the line
for (NSTextCheckingResult* match in matches) {
NSString* matchText = [searchedString substringWithRange:[match range]];
NSRange group1 = [match rangeAtIndex:1];
[arrayOfCO2 addObject:[searchedString substringWithRange:group1]];
}
// search for "T1" at the start of a line, and capture everything to the end of the line
pattern = #"\\nT1\\s*([^\\n\\r]*)";
regex = [NSRegularExpression regularExpressionWithPattern: pattern options:0 error:&error];
matches = [regex matchesInString:searchedString options:0 range: searchedRange];
// for each found match, skip spaces and save the rest of the line
for (NSTextCheckingResult* match in matches) {
NSString* matchText = [searchedString substringWithRange:[match range]];
NSRange group1 = [match rangeAtIndex:1];
[arrayOfT1 addObject:[searchedString substringWithRange:group1]];
}
NSLog(#"");
NSLog(#"CO2:");
NSLog(#"%#", arrayOfCO2);
NSLog(#"");
NSLog(#"T1:");
NSLog(#"%#", arrayOfT1);
This is the result from the sample string you posted:
CO2:
(
"% -0.00",
"% 0.00",
"% -0.00",
"% -0.00"
)
T1:
(
"(null)C -NF-"
)

It seems that the string has new lines (Assuming this is a static text). This would retrieve the values:
Swift :
let stringVal = "CO2 % -23.0\n\nO2 % -0.00\n\nT1 ppm -N/_F"
let arrayNewLine = stringVal.components(separatedBy: "\n")
let strCO2 = arrayNewLine[0].components(separatedBy: " ")[0]
let strO2 = arrayNewLine[1].components(separatedBy: " ")[0]
let strT1 = arrayNewLine[2].components(separatedBy: " ")[0]
Objective C :
NSString *stringVal = #"CO2 % -23.0\n\nO2 % -0.00\n\nT1 ppm -N/_F";
NSArray *arrNewLine = [stringVal componentsSeparatedByString:#"\n"];
NSString *strCO2 = [[[arrNewLine objectAtIndex:0] componentsSeparatedByString:#" "] objectAtIndex:0];
NSString *strO2 = [[[arrNewLine objectAtIndex:1] componentsSeparatedByString:#" "] objectAtIndex:0];
NSString *strT1 = [[[arrNewLine objectAtIndex:2] componentsSeparatedByString:#" "] objectAtIndex:0];

Related

getting certain portion of nsstring

I have string as follows in objective c
NSString *str = #"access_token=E2JmCPLtVySGn-cGGJGGnQ&email=abc#gmail.com";
How can i get only E2JmCPLtVySGn-cGGJGGnQ ?
You can use a Regular Expression (RegEx) to find character patterns.
The pattern matching syntax can be found in the ICU User Guide Regular Expressions
In the example the pattern is: find the first "=" and all characters up to but not including the character "&". In the pattern '(?<=access_token=)" is a look-behind assertion meaning that the "access_token=" must precede the matched text, "[^&]+" the brackets the "[]" mean a character class, the "^" al but the following character, the "+" means one or more.
NSString *str = #"access_token=E2JmCPLtVySGn-cGGJGGnQ&email=abc#gmail.com";
NSString *regexPattern = #"(?<=access_token=)[^&]+";
NSString *found = nil;
NSRange range = [str rangeOfString:regexPattern options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
found = [str substringWithRange:range];
}
NSLog(#"Range: %#", NSStringFromRange(range));
NSLog(#"found: %#", found);
NSLog output if found:
Range: {13, 22}
found: E2JmCPLtVySGn-cGGJGGnQ
There is a method of the NSString class called rangeOfString: that returns an NSRange struct. If you know that your returned value always has the text access_token= and also includes &email and the format is always the same, you can use this rangeOfString: method to sniff out the token.
NSRange accessTokenRange = [str rangeOfString:#"access_token="];
//this would return (0,13) for index:0, length: 13
NSRange emailRange = [str rangeOfString:#"&email="];
//this would return (34,7)
NSInteger tokenLength = ( emailRange.location + 1 ) - accessTokenRange.length;
//the point where &email begins is at index 34, but it starts at 0
//so it's actually the 35th character
//the access_token= string is 13 characters long, so 35-13 = 22
//so you know that the actual token value is 22 characters long
NSRange trueTokenRange = NSMakeRange(accessTokenRange.length,tokenLength);
NSString *tokenSubstring = [str substringWithRange:trueTokenRange];
I don't think my math is off, zero indexing can introduce off by 1 errors if you're not careful, I usually have NSLog going on each range so I can double check where I need to add or subtract 1. But essentially you'll be starting at the 14th character, which is index 13 of the string, and reading the next 22 characters.

Check Objective-C String for specific characters

For an app I'm working on, I need to check if a text field contains only the letters A, T, C, or G. Furthermore, I would like to make specialized error messages for any other inputed characters. ex) "Don't put in spaces." or "The letter b isn't an accepted value." I have read a couple other posts like this, but they are alphanumeric, I only want specified characters.
One approach for you, far from unique:
NString has methods to find substrings, represented as an NSRange of location & offset, made up from characters in a given NSCharacterSet.
The set of what should be in the string:
NSCharacterSet *ATCG = [NSCharacterSet characterSetWithCharactersInString:#"ATCG"];
And the set of what shouldn't:
NSCharacterSet *invalidChars = [ATCG invertedSet];
You can now search for any range of characters consisting of invalidChars:
NSString *target; // the string you wish to check
NSRange searchRange = NSMakeRange(0, target.length); // search the whole string
NSRange foundRange = [target rangeOfCharacterFromSet:invalidChars
options:0 // look in docs for other possible values
range:searchRange];
If there are no invalid characters then foundRange.location will be equal to NSNotFound, otherwise you change examine the range of characters in foundRange and produce your specialised error messages.
You repeat the process, updating searchRange based on foundRange, to find all the runs of invalid characters.
You could accumulate the found invalid characters into a set (maybe NSMutableSet) and produce the error messages at the end.
You can also use regular expressions, see NSRegularExpressions.
Etc. HTH
Addendum
There is a really simple way to address this, but I did not give it as the letters you give suggest to me you may be dealing with very long strings and using provided methods as above may be a worthwhile win. However on second thoughts after your comment maybe I should include it:
NSString *target; // the string you wish to check
NSUInteger length = target.length; // number of characters
BOOL foundInvalidCharacter = NO; // set in the loop if there is an invalid char
for(NSUInteger ix = 0; ix < length; ix++)
{
unichar nextChar = [target characterAtIndex:ix]; // get the next character
switch (nextChar)
{
case 'A':
case 'C':
case 'G':
case 'T':
// character is valid - skip
break;
default:
// character is invalid
// produce error message, the character 'nextChar' at index 'ix' is invalid
// record you've found an error
foundInvalidCharacter = YES;
}
}
// test foundInvalidCharacter and proceed based on it
HTH
Use NSRegulareExpression like this.
NSString *str = #"your input string";
NSRegularExpression *regEx = [NSRegularExpression regularExpressionWithPattern:#"A|T|C|G" options:0 error:nil];
NSArray *matches = [regEx matchesInString:str options:0 range:NSMakeRange(0, str.length)];
for (NSTextCheckingResult *result in matches) {
NSLog(#"%#", [str substringWithRange:result.range]);
}
Also for the options parameter you have to look in the documentation to pick one that fits.
Look at the NSRegularExpression class reference.
Visit: https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html

How to handle a string that comes from URL

Im initializing a string from an URL as follow:
NSString* text = [NSString stringWithContentsOfURL:TheUrl encoding:NSASCIIStringEncoding error:&error];
The URL contains an s19 file, it seems like follow:
S111C019600FBDC09138BDC0353FBDFFCD16D0
S111C0272B024F3986FF393617BDFFB8323968
S110C035308F83000C8F35CCC350ED0AFD15
S111C0426000ED04ED02EC04ED00CCC08ABDFC
after this line I got the data into my text string. then I want to split the string to get an hex array, how can I do that? I was using the next line to get an array but It gives me the next (and it is right):
NSArray *arr = [text componentsSeparatedByString:#"\r\n"];
arr[0] --> S111C019600FBDC09138BDC0353FBDFFCD16D0
How can I split my text string into bytes/words values? something like this:
arr[0] --> C0
arr[1] --> 19
arr[2] --> 60
You can use a for loop and substringWithRange:, building up the range location as you iterate. The length of the range dictates how much you're taking from the original string on each iteration.
Something along the lines of:
NSRange range = NSMakeRange(0, 2);
while (range.location + range.length < sourceString.length) {
[array addObject:[sourceString substringWithRange:range];
range.location += range.length;
}

NSLinguisticTagger - enumerateLinguisticTagsInRange block not limiting range

I'm using enumerateLinguisticTagsInRange within a method like so:
[nonAttributedString enumerateLinguisticTagsInRange:stringRange
scheme:NSLinguisticTagSchemeTokenType
options:NSLinguisticTaggerOmitWhitespace | NSLinguisticTaggerOmitPunctuation | NSLinguisticTaggerJoinNames
orthography:[NSOrthography orthographyWithDominantScript:#"Latn" languageMap:languageMap]
usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
// If the token is a word...
if ([tag isEqualToString:#"Word"])
{
// (And add to the tracking dictionary)
NSMutableDictionary *wordAndRange = [[NSMutableDictionary alloc] init];
[wordAndRange setObject:[NSNumber numberWithInt:(tokenRange.location + tokenRange.length)] forKey:[nonAttributedString substringWithRange:tokenRange]];
[typedWordsAndRanges addObject:wordAndRange];
}
}];
The tagger is working fine but it's not limiting the range to stringRange. It's enumerating through nonAttributedString in it's entirety.
If I include the following logs right above this block:
NSLog(#"########### stringRange.location = %d", stringRange.location);
NSLog(#"########### stringRange.length = %d", stringRange.length);
NSLog(#"########### substring = %#", [nonAttributedString substringWithRange:stringRange]);
I get the following output:
2013-03-18 21:06:27.744 WEJ[13231:c07] ########### stringRange.location = 10
2013-03-18 21:06:27.745 WEJ[13231:c07] ########### stringRange.length = 4
2013-03-18 21:06:27.805 WEJ[13231:c07] ########### substring = de
So stringRange is correct. However, it's still enumerating through nonAttributedString in it's entirety.
What am I doing wrong?
The docs for enumerateTagsInRange:scheme:options:usingBlock: state:
It is important to note that this method will return the ranges of all tokens that intersect the given range.
If you want to consider only those tokens that are completely in stringRange, you'll have to retrieve that substring from nonAttributedString before invoking enumerateTagsInRange::::.

regular expression in iOS

I am looking for a regular expression to match the following -100..100:0.01. The meaning of this expression is that the value can increment by 0.01 and should be in the range -100 to 100.
Any help ?
You could use NSRegularExpression instead. It does support \b, btw, though you have to escape it in the string:
NSString *regex = #"\\b-?1?[0-9]{2}(\\.[0-9]{1,2})?\\b";
Though, I think \\W would be a better idea, since \\b messes up detecting the negative sign on the number.
A hopefully better example:
NSString *string = <...your source string...>;
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"\\W-?1?[0-9]{2}(\\.[0-9]{1,2})?\\W"
options:0
error:&error];
NSRange range = [regex rangeOfFirstMatchInString:string
options:0
range:NSMakeRange(0, [string length])];
NSString *result = [string substringWithRange:range];
I hope this helps. :)
EDIT: fixed based on the below comment.
(\b|-)(100(\.0+)?|[1-9]?[0-9](\.[0-9]{1,2})?\b
Explanation:
(\b|-) # word boundary or -
( # Either match
100 # 100
(\.0+)? # optionally followed by .00....
| # or match
[1-9]? # optional "tens" digit
[0-9] # required "ones" digit
( # Try to match
\. # a dot
[0-9]{1,2}# followed by one or two digits
)? # all of this optionally
) # End of alternation
\b # Match a word boundary (make sure the number stops here).
Why do you want to use a regular expression? Why not just do something like (in pseudocode):
is number between -100 and 100?
yes:
multiply number by 100
is number an integer?
yes: you win!
no: you don't win!
no:
you don't win!
if(val>= -100 && val <= 100)
{
NSString* valregex = #"^[+|-]*[0-9]*.[0-9]{1,2}";
NSPredicate* valtest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", valregex];
ret = [valtest evaluateWithObject:txtLastname.text];
if (!ret)
{
[alert setMessage:NSLocalizedString(#"More than 2 decimals", #"")];
[alert show];
}
}
works fine.. Thnx for the efforts guys !

Resources