I am quite confused on how to extract the value of a var in a js executed in UIWebView, my code is:
NSString * js = [NSString stringWithFormat:#"var script = document.createElement('script');"
"script.type = 'text/javascript';"
"script.text = \"function getTopLeftCorner() { "
"var el = document.elementFromPoint(%f, %f);"
"var pos = [el.offsetLeft, el.offsetTop];"
"var parent = el.offsetParent;"
"if (parent != el) {"
"while (parent) {"
"pos[0] += parent.offsetLeft;"
"pos[1] += parent.offsetTop;"
"parent = parent.offsetParent;"
"}"
"}"
"return pos;"
"}\";"
"document.getElementsByTagName('head')[0].appendChild(script);"
, pt.x, pt.y];
[self stringByEvaluatingJavaScriptFromString:js];
NSString * result = [self stringByEvaluatingJavaScriptFromString:#"getTopLeftCorner()"];
NSLog(#"RESULT IS %#", result);
Any idea why the result is empty?
Your first statement NSString * js = [NSString stringWithFormat:#"var script closes the string at the end of the line, then follows several more C strings. You should be getting a syntax error from the Objective-C compiler.
To concatenate strings use [NSString stringWithFormat:#"%#/%#/%#", three, two, one];. Read through the class reference for a greater explanation of the method.
Related
I want to solve a conditional equation in iOS:
The equation I get from database is in NSString format, for example:
if((height > 0), (weight+ 2 ), ( weight-1 ) )
As per our understanding, if I parse the above string and separateheight>0condition, it will be in the NSString format. But to evaluate it how do I convert the string to a conditional statement?
Once the conditional statement is obtained the equation can be solved by converting it to a ternary equation as follows:
Bool status;
NSString *condition=#” height>0”;
If(condition) //But condition is treated as a string and not as a conditional statement.
{
status=True;
}
else
{
status=False;
}
Return status ? weight+ 2 : weight-1;`
Also the equations can dynamically change, so they cannot be hard coded. In short how do I solve this equation which I get as a NSString.
Thank you for your patience!
DDMathParser author here...
To expand on Jonathan's answer, here's how you could do it entirely in DDMathParser. However, to parse the string as-is, you'll need to do two things.
First, you'll need to create an if function:
DDMathEvaluator *evaluator = [DDMathEvaluator sharedMathEvaluator];
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError *__autoreleasing *error) {
if ([args count] == 3) {
DDExpression *condition = [args objectAtIndex:0];
DDExpression *resultExpression = nil;
NSNumber *conditionValue = [condition evaluateWithSubstitutions:vars evaluator:eval error:error];
if ([conditionValue boolValue] == YES) {
resultExpression = [args objectAtIndex:1];
} else {
resultExpression = [args objectAtIndex:2];
}
NSNumber *result = [resultExpression evaluateWithSubstitutions:vars evaluator:eval error:error];
return [DDExpression numberExpressionWithNumber:result];
}
return nil;
} forName:#"if"];
This creates the if() function, which takes three parameters. Depending on how the first parameter evaluates, it either evaluates to the result of the second or third parameter.
The other thing you'll need to do is tell the evaluator what height and weight mean. Since they don't start with a $ character, they get interpreted as functions, and not variables. If they started with a $, then it would be as simple as evaluating it like this:
NSString *expression = #"if(($height > 0), ($weight+ 2 ), ( $weight-1 ) )";
NSDictionary *variables = #{#"height" : #42, #"weight" : #13};
NSNumber *result = [expression evaluateWithSubstitutions:variables evaluator:evaluator error:nil];
However, since they don't start with a $, they're functions, which means you need to tell the evaluator what the functions evaluate to. You could do this by creating functions for both height and weight, just like you did for if:
[evaluator registerFunction:^DDExpression *(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
return [DDExpression numberExpressionWithNumber:#42];
} forName:#"height"];
Alternatively, you could make it a bit more dynamic and use the functionResolver block of DDMathEvaluator, which is a block that returns a block (woooooo) and would look like this:
NSDictionary *values = #{#"height": #42, #"weight": #13};
[evaluator setFunctionResolver:^DDMathFunction(NSString *name) {
DDMathFunction f = ^(NSArray *args, NSDictionary *vars, DDMathEvaluator *eval, NSError **error) {
NSNumber *n = [values objectForKey:name];
if (!n) { n = #0; }
return [DDExpression numberExpressionWithNumber:n];
};
return f;
}];
With those two pieces in place (registering if and providing the values of height and weight), you can do:
NSString *expression = #"if((height > 0), (weight+ 2 ), ( weight-1 ) )";
NSNumber *result = [expression evaluateWithSubstitutions:nil evaluator:evaluator error:nil];
... and get back the proper result of #15.
(I have plans to make DDMathParser allow unknown functions to fall back to provided variable values, but I haven't quite finished it yet)
you will have to write your own interpreter or find one that supports this kind of expressions.
The first part (the condition) can be evaluated by NSPredicate. For the second part (the calculation) you will need some math expression evaluation. Try this out https://github.com/davedelong/DDMathParser. Maybe you can do both with DDMathParser but i am not sure.
I want to string string from the end of string, is there any api function of string which ONLY removes Space and Newline from END of string.
I wrote manual code to search character from end of string and remove space and newline but it may slow the process.
API function needed..
Thanks in advance
try this one may be it helps you,
-(NSString *)removeEndSpaceFrom:(NSString *)strtoremove{
NSUInteger location = 0;
unichar charBuffer[[strtoremove length]];
[strtoremove getCharacters:charBuffer];
int i = 0;
for ( i = [strtoremove length]; i >0; i--){
if (![[NSCharacterSet whitespaceCharacterSet] characterIsMember:charBuffer[i - 1]]){
break;
}
}
return [strtoremove substringWithRange:NSMakeRange(location, i - location)];
}
and
NSString *string = #" this text has spaces before and after ";
NSString *trimmedString = [self removeEndSpaceFrom:string];
NSLog(#"%#",trimmedString);
My app gets the string from an RSS feed for the preview image. It displays in this format:
<p><img class="alignnone size-full wp-image-22" title="144x144" src="http://316apps.com/LakesideNews/wp-content/uploads/2012/05/144x1443.png" alt="" width="144" height="144" /></p>
hi
I am parsing the rss using GDATAXML and tutorial from Ray Wenderlich's blog. I set up an NSString to the value that is given in the RSS for the image. I then set up an NSLog with that string. What the NSLog returns is what I had put in the original post. Is there a way to subString it to get just the part between " "?
use NSRange, but you'll need to determine the start point and length (the position of the two quotes)
[untested code]
int idStart = 0;
int idEnd = 0;
for (int f = 0; f < [initialString length]; f++) {
NSRange myRangeStart;
myRangeStart.location = f;
myRangeStart.length = 1;
substr = [urlStr substringWithRange:myRangeStart];
if ( idStart == 0) {
if ([substr isEqualToString:#"\""]) {
idStart = f;
}
} else {
if ([substr isEqualToString:#"\""] && f > idStart) {
idEnd = f;
}
}
}
NSString* substring = #"";
NSRange myRange;
myRange.location = idStart+1;
myRange.length = idEnd-idStart-1;
substring = [initialString substringWithRange:myRange];
[/untested code]
Take a look at NSXMLParser in Apple's documentation. You should be able to use the string as NSData and parse it with that object.
I would like to get the percent encoded string for these specific letters, how to do that in objective-c?
Reserved characters after percent-encoding
! * ' ( ) ; : # & = + $ , / ? # [ ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D
Percent-encoding wiki
Please test with this string and see if it do work:
myURL = #"someurl/somecontent"
I would like the string to look like:
myEncodedURL = #"someurl%2Fsomecontent"
I tried with the stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding already but it does not work, the result is still the same as the original string. Please advice.
I've found that both stringByAddingPercentEscapesUsingEncoding: and CFURLCreateStringByAddingPercentEscapes() are inadequate. The NSString method misses quite a few characters, and the CF function only lets you say which (specific) characters you want to escape. The proper specification is to escape all characters except a small set.
To fix this, I created an NSString category method to properly encode a string. It will percent encoding everything EXCEPT [a-zA-Z0-9.-_~] and will also encode spaces as + (according to this specification). It will also properly handle encoding unicode characters.
- (NSString *) URLEncodedString_ch {
NSMutableString * output = [NSMutableString string];
const unsigned char * source = (const unsigned char *)[self UTF8String];
int sourceLen = strlen((const char *)source);
for (int i = 0; i < sourceLen; ++i) {
const unsigned char thisChar = source[i];
if (thisChar == ' '){
[output appendString:#"+"];
} else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
(thisChar >= 'a' && thisChar <= 'z') ||
(thisChar >= 'A' && thisChar <= 'Z') ||
(thisChar >= '0' && thisChar <= '9')) {
[output appendFormat:#"%c", thisChar];
} else {
[output appendFormat:#"%%%02X", thisChar];
}
}
return output;
}
The iOS 7 SDK now has a better alternative tostringByAddingPercentEscapesUsingEncoding that does let you specify that you want all characters escaped except certain allowed ones. It works well if you are building up the URL in parts:
NSString * unescapedQuery = [[NSString alloc] initWithFormat:#"?myparam=%d", numericParamValue];
NSString * escapedQuery = [unescapedQuery stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:#"http://ExampleOnly.com/path.ext%#", escapedQuery];
Although it's less often that the other parts of the URL will be variables, there are constants in the NSURLUtilities category for those as well:
[NSCharacterSet URLHostAllowedCharacterSet]
[NSCharacterSet URLUserAllowedCharacterSet]
[NSCharacterSet URLPasswordAllowedCharacterSet]
[NSCharacterSet URLPathAllowedCharacterSet]
[NSCharacterSet URLFragmentAllowedCharacterSet]
[NSCharacterSet URLQueryAllowedCharacterSet] includes all of the characters allowed in the query part of the URL (the part starting with the ? and before the # for a fragment, if any) including the ? and the & or = characters, which are used to delimit the parameter names and values. For query parameters with alphanumeric values, any of those characters might be included in the values of the variables used to build the query string. In that case, each part of the query string needs to be escaped, which takes just a bit more work:
NSMutableCharacterSet * URLQueryPartAllowedCharacterSet; // possibly defined in class extension ...
// ... and built in init or on first use
URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[URLQueryPartAllowedCharacterSet removeCharactersInString:#"&+=?"]; // %26, %3D, %3F
// then escape variables in the URL, such as values in the query and any fragment:
NSString * escapedValue = [anUnescapedValue stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSString * escapedFrag = [anUnescapedFrag stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:#"http://ExampleOnly.com/path.ext?myparam=%##%#", escapedValue, escapedFrag];
NSURL * url = [[NSURL alloc] initWithString:urlString];
The unescapedValue could even be an entire URL, such as for a callback or redirect:
NSString * escapedCallbackParamValue = [anAlreadyEscapedCallbackURL stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSURL * callbackURL = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"http://ExampleOnly.com/path.ext?callback=%#", escapedCallbackParamValue]];
Note: Don't use NSURL initWithScheme:(NSString *)scheme host:(NSString *)host path:(NSString *)path for a URL with a query string because it will add more percent escapes to the path.
NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
It won't replace your string inline; it'll return a new string. That's implied by the fact that the method starts with the word "string". It's a convenience method to instantiate a new instance of NSString based on the current NSString.
Note--that new string will be autorelease'd, so don't call release on it when you're done with it.
NSString's stringByAddingPercentEscapesUsingEncoding: looks like what you're after.
EDIT: Here's an example using CFURLCreateStringByAddingPercentEscapes instead. originalString can be either an NSString or a CFStringRef.
CFStringRef newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, NULL, CFSTR("!*'();:#&=+#,/?#[]"), kCFStringEncodingUTF8);
Please note that this is untested. You should have a look at the documentation page to make sure you understand the memory allocation semantics for CFStringRef, the idea of toll-free bridging, and so on.
Also, I don't know (off the top of my head) which of the characters specified in the legalURLCharactersToBeEscaped argument would have been escaped anyway (due to being illegal in URLs). You may want to check this, although it's perhaps better just to be on the safe side and directly specify the characters you want escaped.
I'm making this answer a community wiki so that people with more knowledge about CoreFoundation can make improvements.
Following the RFC3986 standard, here is what I'm using for encoding URL components:
// https://tools.ietf.org/html/rfc3986#section-2.2
let rfc3986Reserved = NSCharacterSet(charactersInString: "!*'();:#&=+$,/?#[]")
let encoded = "email+with+plus#example.com".stringByAddingPercentEncodingWithAllowedCharacters(rfc3986Reserved.invertedSet)
Output: email%2Bwith%2Bplus%40example.com
If you are using ASI HttpRequest library in your objective-c program, which I cannot recommend highly enough, then you can use the "encodeURL" helper API on its ASIFormDataRequest object. Unfortunately, the API is not static so maybe worth creating an extension using its implementation in your project.
The code, copied straight from the ASIFormDataRequest.m for encodeURL implementation, is:
- (NSString*)encodeURL:(NSString *)string
{
NSString *newString = NSMakeCollectable([(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding])) autorelease]);
if (newString) {
return newString;
}
return #"";
}
As you can see, it is essentially a wrapper around CFURLCreateStringByAddingPercentEscapes that takes care of all the characters that should be properly escaped.
Before I noticed Rob's answer, which appears to work well and is preferred as it's cleaner, I went ahead and ported Dave's answer to Swift. I'll leave it here in case anyone is interested:
public extension String {
// For performance, I've replaced the char constants with integers, as char constants don't work in Swift.
var URLEncodedValue: String {
let output = NSMutableString()
guard let source = self.cStringUsingEncoding(NSUTF8StringEncoding) else {
return self
}
let sourceLen = source.count
var i = 0
while i < sourceLen - 1 {
let thisChar = source[i]
if thisChar == 32 {
output.appendString("+")
} else if thisChar == 46 || thisChar == 45 || thisChar == 95 || thisChar == 126 ||
(thisChar >= 97 && thisChar <= 122) ||
(thisChar >= 65 && thisChar <= 90) ||
(thisChar >= 48 && thisChar <= 57) {
output.appendFormat("%c", thisChar)
} else {
output.appendFormat("%%%02X", thisChar)
}
i++
}
return output as String
}
}
In Swift4:
var str = "someurl/somecontent"
let percentEncodedString = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
Continued from the last question here: Log method name in Obj-C . I just wondered if there is a way to print out the variable name as well. For example:
NSString *name = "vodkhang";
NCLog(#"%#", name);
and I hope that the output should be:
name: vodkhang
Just to summarize the previous post, currently, I can print out the class name, method name and the line number when I call
NCLog(#"Hello World");
<ApplicationDelegate:applicationDidFinishLaunching:10>Hello world
with
#define NCLog(s, ...) NSLog(#"<%#:%d> %#", __FUNCTION__, __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__])
#define logIntVariable(x) NSLog( #"Value of %s = %d",#x, x)
- (void) myRoutine {
int intValue = 5;
logIntVariable(intValue);
}