function to get the file name of an URL - iphone

I have some source code to get the file name of an url
for example:
http://www.google.com/a.pdf
I hope to get a.pdf
because the way to join 2 NSStrings I can get is 'appendString' which only for adding a string at right side, so I planned to check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop the checking, return string fdp.a , after that I change fdp.a to a.pdf
source codes are below
-(NSMutableString *) getSubStringAfterH : originalString:(NSString *)s0
{
NSInteger i,l;
l=[s0 length];
NSMutableString *h=[[NSMutableString alloc] init];
NSMutableString *ttt=[[NSMutableString alloc] init ];
for(i=l-1;i>=0;i--) //check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop
{
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
if([ttt isEqualToString:#"/"])
{
break;
}
else
{
[h appendString:ttt];
}
}
[ttt release];
NSMutableString *h1=[[[NSMutableString alloc] initWithFormat:#""] autorelease];
for (i=[h length]-1;i>=0;i--)
{
NSMutableString *t1=[[NSMutableString alloc] init ];
t1=[h substringWithRange:NSMakeRange(i, 1)];
[h1 appendString:t1];
[t1 release];
}
[h release];
return h1;
}
h1 can reuturn the coorect string a.pdf, but if it returns to the codes where it was called, after a while system reports
'double free
*** set a breakpoint in malloc_error_break to debug'
I checked a long time and foudn that if I removed the code
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
everything will be Ok (of course getSubStringAfterH can not returns the corrent result I expected.), no error reported.
I try to fix the bug a few hours, but still no clue.
Welcome any comment
Thanks
interdev

The following line does the job if url is a NSString:
NSString *filename = [url lastPathComponent];
If url is a NSURL, then the following does the job:
NSString *filename = [[url path] lastPathComponent];

Try this:
Edit: from blow comment
NSString *url = #"http://www.google.com/a.pdf";
NSArray *parts = [url componentsSeparatedByString:#"/"];
NSString *filename = [parts lastObject];

I think if you have already had the NSURL object, there is lastPathComponent method available from the iOS 4 onwards.
NSURL *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *filename = [url lastPathComponent];

Swift 3
Let's say that your url is http://www.google.com/a.pdf
let filename = url.lastPathComponent
\\filename = "a.pdf"

This is more error free and meant for getting the localized name in the URL.
NSString *localizedName = nil;
[url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];

I haven't tried this yet, but it seems like you might be trying to do this the hard way. The iPhone libraries have the NSURL class, and I imagine that you could simply do:
NSString *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *path = [url path];
Definitely look for a built in function. The libraries have far more testing and will handle the edge cases better than anything you or I will write in an hour or two (generally speaking).

Related

Remove last portion of the NSURL: iOS

I am trying to remove just the last part of the url, Its a FTP URL.
Suppose, I have a URL like: > ftp://ftp.abc.com/public_html/somefolder/. After removing the last portion I should have it as: ftp://ftp.abc.com/public_html/.
I have tried using stringByDeletingLastPathComponenet and URLByDeletingLastPathComponent, but they dont remove the last portion correctly. They change the entire looks of the url.
for instance, after using the above said methods, here is the URL format i get ftp:/ftp.abc.com/public_html/. It removes one "/" in "ftp://", which is crashing my program.
How is it possible to removve just the last part without disturbing the rest of the URL ?
UPDATE:
NSURL * stringUrl = [NSURL URLWithString:string];
NSURL * urlByRemovingLastComponent = [stringUrl URLByDeletingLastPathComponent];
NSLog(#"%#", urlByRemovingLastComponent);
Using above code, I get the output as :- ftp:/ftp.abc.com/public_html/
Hmm. URLByDeletingLastPathComponent works perfectly given the above input.
NSURL *url = [NSURL URLWithString:#"ftp://ftp.abc.com/public_html/somefolder/"];
NSLog(#"%#", [url URLByDeletingLastPathComponent]);
returns
ftp://ftp.abc.com/public_html/
Do you have some sample code that is yielding improper results?
Max
Now try
NSString* filePath = #"ftp://ftp.abc.com/public_html/somefolder/.";
NSArray* pathComponents = [filePath pathComponents];
NSLog(#"\n\npath=%#",pathComponents);
if ([pathComponents count] > 2) {
NSArray* lastTwoArray = [pathComponents subarrayWithRange:NSMakeRange([pathComponents count]-2,2)];
NSString* lastTwoPath = [NSString pathWithComponents:lastTwoArray];
NSLog(#"\n\nlastTwoArray=%#",lastTwoPath);
NSArray *listItems = [filePath componentsSeparatedByString:lastTwoPath];
NSLog(#"\n\nlist item 0=%#",[listItems objectAtIndex:0]);
}
output
path=(
"ftp:",
"ftp.abc.com",
"public_html",
somefolder,
"."
)
lastTwoArray =somefolder/.
list item 0 =ftp://ftp.abc.com/public_html/
An example of how to extract the last part of NSURL. In this case the location of the file. Sqlite core data
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"CoreAPI.sqlite"];
NSString *localPath = [storeURL absoluteString];
NSArray* pathComponents = [localPath pathComponents];
NSLog(#"%#",[pathComponents objectAtIndex:6]);
NSString * nombre = [NSString stringWithFormat:#"%#", [pathComponents objectAtIndex:6]];
This code returns me the name of the file CoreAPI.sqlite

CHCSV Error : unable to allocate memory for length

I want to parse a .csv file. For this I use the CHCSV Parser. But when I push into the view where the parser should start parsing, the app crashes.
Terminating app due to uncaught exception 'NSMallocException', reason:
'* -[NSConcreteMutableData appendBytes:length:]: unable to allocate
memory for length (4294967295)'
NSString *filePath = #"http://somewhere.com/test.csv";
NSString *fileContent = [NSString stringWithContentsOfURL:[NSURL URLWithString:filePath] encoding:NSUTF8StringEncoding error:nil];
self.csvParser = [[CHCSVParser alloc] initWithContentsOfCSVFile:fileContent];
Edit:
I'm developing for iOS 6+. Thanks for the great comments and answers. I hope to get the right solution.
Input Stream
It doesn't work. When I want to work with the input stream the app crashes because of the wrong encoding.
Incompatible integer to pointer conversion sending 'int' to
parameter of type 'NSStringEncoding *' (aka 'unsigned int *')
NSData *downloadData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://example.com/test.csv"]];
NSInputStream *stream = [NSInputStream inputStreamWithData:downloadData];
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:NSUTF8StringEncoding delimiter:#";"];
self.csvParser.delegate = self;
[self.csvParser parse];
CSV-String
NSString *filePath = #"http://example.com/test.csv";
NSString *fileContent = [NSString stringWithContentsOfURL:[NSURL URLWithString:filePath] encoding:NSUTF8StringEncoding error:nil];
self.csvParser = [[CHCSVParser alloc] initWithCSVString:fileContent];
self.csvParser.delegate = self;
[self.csvParser parse];
This parse only (null).
Final Edit: Dave, the author of CHCSVParser, updated his code on github, so this problem should be solved when you use the most recent version. Get it now!
Okay, here we go:
First add the following code in CHCSVParser.m:
In method - (void)_sniffEncoding at the very beginning you have:
uint8_t bytes[CHUNK_SIZE];
NSUInteger readLength = [_stream read:bytes maxLength:CHUNK_SIZE];
[_stringBuffer appendBytes:bytes length:readLength];
[self setTotalBytesRead:[self totalBytesRead] + readLength];
change it to:
uint8_t bytes[CHUNK_SIZE];
NSUInteger readLength = [_stream read:bytes maxLength:CHUNK_SIZE];
if (readLength > CHUNK_SIZE) {
readLength = CHUNK_SIZE;
}
[_stringBuffer appendBytes:bytes length:readLength];
[self setTotalBytesRead:[self totalBytesRead] + readLength];
After that changed I got only null values so I changed the file path (in the sample project it is located in the main(), however I did the parsing in viewDidLoad.
Make sure you copied the file in your bundle directory for that to work!
file = [NSBundle pathForResource:#"Test" ofType:#"scsv" inDirectory:[[NSBundle mainBundle] bundlePath]];
Edit:
When you say you need to download the file you can do following (but notice that this is quick and dirty solution especially on mobile devices)
NSData *downloadData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.yourdomain.tld/Test.scsv"]];
NSInputStream *stream = [NSInputStream inputStreamWithData:downloadData];
The last line is the important one here you need to change.
Hope that solves your issue.
Edit 2:
I've just created a repository with a demo project for you where the code actually works. Perhaps you can find out what you do wrong (or at least different). Here is the link.
Edit 3:
Change
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:NSUTF8StringEncoding delimiter:#";"];
to
self.csvParser = [[CHCSVParser alloc] initWithInputStream:stream usedEncoding:&encoding delimiter:';'];

UIWebView URL from String without http://

So I check if the string starts with "http://" using the code below, and then I want to add "http://" so that I'm able to open the page in UIWebView.
NSString *firstString = [NSString stringWithFormat:#"%#", URL.text];
NSString *check = [NSString stringWithFormat:#"%#", #"http://"];
if (firstString != check) {
NSString *newString = [NSString stringWithFormat:#"http://%#", URL.text];
newString = [newString substringWithRange:NSMakeRange(7, newString.length - 7)];
URL.text = newString;
}
[WebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:URL.text]]];`
This doesn't work for some reason.
Do you know why?
Somebody posted as I was writing, but either way, here's an answer:
You are making this too difficult. You simply need to use hasPrefix to check for "http". As an example, I use this for my unified search/url bar.
- (IBAction)go:(id)sender {
NSString *inputString = [searchField stringValue];
NSString *outputString = [inputString stringByReplacingOccurrencesOfString:#" " withString:#"+"];
if ([inputString hasPrefix:#"http://"]) {
//Has Prefix
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:inputString]]];
}
else
{
//Does not have prefix. Do what you want here. I google it.
NSString *googleString = #"http://google.com/search?q=";
NSString *searchString = [NSString stringWithFormat:#"%#%#", googleString, outputString];
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:searchString]]];
}
}
That is for googling instead, you could keep using NSString *newString = [NSString stringWithFormat:#"http://%#", URL.text];
You could add a few more checks as well if you wanted to. Good luck!
firstString != check checks to see if both objects point to the same location in memory. [firstString isEqualToString:check] checks if the two strings are equal. However, what you most likely want to do is if(![firstString hasPrefix:check]). This will check to make sure firstString does not start with check, then you can append check to the start of it. Alternatively, you can do firstString = [firstString stringByReplacingOccurrencesOfString:#"http://" withString:#""];, and then you know it will never start with #"http://"
Try printing what URL.text is before the loadRequest line via NSLog(#"%#",URL.text);
Also the preferred check condition would be if (![firstString isEqualToString:check]) {}

How to get find and get URL in a NSString in iPhone?

I have a text with http:// in NSString. I want to get that http link from the NSString. How can i get the link/url from the string? Eg: 'Stack over flow is very useful link for the beginners https://stackoverflow.com/'. I want to get the 'https://stackoverflow.com/' from the text. How can i do this? Thanks in advance.
I am not sure what you exactly mean by link but if you want to convert your NSString to NSURL than you can do the following:
NSString *urlString = #"http://somepage.com";
NSURL *url = [NSURL URLWithString:urlString];
EDIT
This is how to get all URLs in a given NSString:
NSString *str = #"This is a grate website http://xxx.xxx/xxx you must check it out";
NSArray *arrString = [str componentsSeparatedByString:#" "];
for(int i=0; i<arrString.count;i++){
if([[arrString objectAtIndex:i] rangeOfString:#"http://"].location != NSNotFound)
NSLog(#"%#", [arrString objectAtIndex:i]);
}
Rather than splitting the string into an array and messing about that way, you can just search for the substring beginning with #"http://":
NSString *str = #"Stack over flow is very useful link for the beginners http://stackoverflow.com/";
// get the range of the substring starting with #"http://"
NSRange rng = [str rangeOfString:#"http://" options:NSCaseInsensitiveSearch];
// Set up the NSURL variable to hold the created URL
NSURL *newURL = nil;
// Make sure that we actually have found the substring
if (rng.location == NSNotFound) {
NSLog(#"URL not found");
// newURL is initialised to nil already so nothing more to do.
} else {
// Get the substring from the start of the found substring to the end.
NSString *urlString = [str substringFromIndex:rng.location];
// Turn the string into an URL and put it into the declared variable
newURL = [NSURL URLWithString:urlString];
}
try this :
nsstring *str = #"Stack over flow is very useful link for the beginners http://stackoverflow.com/";
nsstring *http = #"http";
nsarray *arrURL = [str componentsSeparatedByString:#"http"];
this will give two objects in the nsarray. 1st object will be having:Stack over flow is very useful link for the beginners and 2nd will be : ://stackoverflow.com/ (i guess)
then you can do like:
NSString *u = [arrURL lastObject];
then do like:
nsstring *http = [http stringByAppendingFormat:#"%#",u];
Quite a lengthy,but i think that would work for you. Hope that helps you.

Memory management issues with retrieving particular lines of text from string

I am kind of new to iOS development.
I want to retrieve strings from the text(.rtf) file I have. The file is within my application main bundle. It's content are:
#start word1 First word end word2 Second word end //lots of things to be added later
Code:
path = [[NSBundle mainBundle]pathForResource:#"words" ofType:#"rtf"];
if(path)
{
NSLog(#"path exists");
}
NSError *error = nil;
NSString *file = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"error");
}
NSString *finalword= [[NSString alloc]init ];
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
i++;
NSLog(#"%#",startfrom);
NSString *wordoftheday = [[NSString alloc]init ];
NSScanner *scanner = [NSScanner scannerWithString:file];
[scanner scanUpToString:startfrom intoString:nil];
[scanner scanUpToString:#"end" intoString:&wordoftheday];
finalword = [wordoftheday substringFromIndex:[startfrom length]];
NSLog(#"%#",finalword);
Word.text = final word; //change label text
//[final word release];
//[wordoftheday release];
//[file release];
Code is working fine but it leaves me with memory management issues. App crashes if I release the variables in the last commented code.
Also this method is in my viewdidload. I want the label to change text when user click a button. I will have to write the same code again in that method which leaves me with more memory issue.
So looking at these one by one, focusing on the memory issues and not the overall strategy here:
NSString *finalword= [[NSString alloc]init ];
Here you alloc/init a new immutable and empty NSString, and then you end up overwriting the pointer to this later anyway. You should just delete this line. And then you'll need to move the declaration down a few lines to this:
NSString *finalword = [wordoftheday substringFromIndex:[startfrom length]];
Then you have:
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
This one you need to release later. Or just change it to:
NSString *startfrom = [NSString stringWithFormat:#"word%i",i+1];
Then you have:
NSString *wordoftheday = [[NSString alloc]init ];
Same story as finalword. Except that you do need to define this variable so you can pass it to the scanner later. So change it to:
NSString *wordoftheday = nil;
And lastly, you can release 'file'. That is fine. But you don't want to release 'wordoftheday' or 'finalword' because you don't own those strings. You did not create them yourself.
And one other note:
if(error)
That is not the correct way to check for an error in loading 'file'. You should check the return from the method and then look for an error if and only if the return value was nil. So change that line to:
if(!file)
(OK, that wasn't really a memory issue, but a bug I did notice.)
I think that's all of it at least as far as memory issues. I hope that helps.
make those variables as member variables and release in the dealloc