How to encode odd HTML characters with Xcode? - html

I need to save a HTML page in my app, and when characters like "€" are found, the saved file displays them wrong.
I tried several encodings but none solves this, is there any solution?
I have also tried to replace the characters for the HTML name, but it still doesn't work.
Here's my code:
NSString *HTML = [web stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('html')[0].innerHTML;"];
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [path objectAtIndex:0],#"code.html"];
int enc_arr[] = {
NSISOLatin1StringEncoding, // ESP
NSUTF8StringEncoding, // UTF-8
NSShiftJISStringEncoding, // Shift_JIS
NSJapaneseEUCStringEncoding, // EUC-JP
NSISO2022JPStringEncoding, // JIS
NSASCIIStringEncoding // ASCII
};
NSData *urlData= nil;
for (int i=0; i<6; i++) {
urlData = [HTML dataUsingEncoding:enc_arr[i]];
if (urlData!=nil) {
break;
}
}
[urlData writeToFile:filePath atomically:YES];

See these methods of NSString:
- (NSStringEncoding)smallestEncoding
- (NSStringEncoding)fastestEncoding
or just use method below with flag set to YES :
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding allowLossyConversion:(BOOL)flag
but with this one you can loose some characters.

Ok I finally did it, it's not the best way but the only one that worked for me and without using external libraries:
-(NSString*)escapeHTML:(NSString*)code{
NSMutableArray *maExceptions = [[NSMutableArray alloc] initWithObjects: #"Œ", #"œ", #"Š", #"š", #"Ÿ", #"ƒ", #"‘", #"’", #"‚", #"“", #"”", #"„", #"†", #"‡", #"•", #"…", #"‰", #"€", #"™", nil];
for (int i=0; i<[maExceptions count]; i++) {
code = [code stringByReplacingOccurrencesOfString:[maExceptions objectAtIndex:i] withString:[NSString stringWithFormat:#"&#x%x;",[[maExceptions objectAtIndex:i] characterAtIndex:0]]];
}
return code;
}

Related

NSString remove html tags, keep <Text in angle brackets>

How do I remove html tags from NSString, but keep any <Text in angle brackets>?
Like <p>123 <Hello> abc</p> -> 123 <Hello> abc
I have tried all kinds of regexp, scanner and XML Parser solutions, but they remove <Text in angle brackets> as well as tags.
The only solution that fit me was to use an NSAttributedString with options
NSAttributedString *str = [[NSAttributedString alloc] initWithData:utf8Data
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)}
documentAttributes:nil
error:nil];
NSString *result = [str string];
but this approach employs WebKit and consumes too much memory for my task.
So, how do I strip tags from NSString, keeping <Text in angle brackets> without using any kind of WebKit/UIWebView and so on?
I asked a similar questionma while ago, may be some of the answers can help you out.
If you do need the full HTML parser and just want to strip HTML tags out, a NSString category might be useful (this one is a modified category by mwaterfal):
- (NSString *)stringByStrippingTags {
// Find first & and short-cut if we can
NSUInteger ampIndex = [self rangeOfString:#"<" options:NSLiteralSearch].location;
if (ampIndex == NSNotFound) {
return [NSString stringWithString:self]; // return copy of string as no tags found
}
// Scan and find all tags
NSScanner *scanner = [NSScanner scannerWithString:self];
[scanner setCharactersToBeSkipped:nil];
NSMutableSet *tags = [[NSMutableSet alloc] init];
NSString *tag;
do {
// Scan up to <
tag = nil;
[scanner scanUpToString:#"<" intoString:NULL];
[scanner scanUpToString:#">" intoString:&tag];
if (tag) {
NSString *t = [[NSString alloc] initWithFormat:#"%#>", tag];
[tags addObject:t];
}
} while (![scanner isAtEnd]);
NSMutableString *result = [[NSMutableString alloc] initWithString:self];
NSString *finalString;
NSString *replacement;
for (NSString *t in tags) {
replacement = #" ";
if ([t isEqualToString:#"<a>"] ||
[t isEqualToString:#"</a>"] ||
[t isEqualToString:#"<span>"] ||
[t isEqualToString:#"</span>"] ||
[t isEqualToString:#"<strong>"] ||
[t isEqualToString:#"</strong>"] ||
[t isEqualToString:#"<em>"] ||
[t isEqualToString:#"</em>"]) {
replacement = #"";
}
[result replaceOccurrencesOfString:t
withString:replacement
options:NSLiteralSearch
range:NSMakeRange(0, result.length)];
}
// Remove multi-spaces and line breaks
return = [result stringByRemovingNewLinesAndWhitespace];
}

Create Table in iOS

I want to make table in HTML and embded in objective c and after load in HTML . I am using this code i am not getting table.
myArray=[[NSMutableArray alloc]init];
array=[NSArray arrayWithObjects:#"1",#"2",#"3", nil];
NSString *embedHtml=#"<html><head><title>First</title><style>table , td, table , tr, th{border:1px solid #333333;padding:2px;}</style></head><body><table ><tr><th>Col1</th><th>Col2</th><th>Col3</th><th>Col4</th><th>Col5</th></tr>";
for (int i=0; i<3; i++) {
thiss= [NSString stringWithFormat:#"<tr><td>Data1</td><td> %#</td><td>Data1</td><td>Data1</td><td>Data1</td></tr>",[array objectAtIndex:i]];
[myArray addObject:thiss];
}
thiss =[embedHtml stringByAppendingString:[myArray objectAtIndex:0]];
NSString *idd=[thiss stringByAppendingString:#"</table></body></html>"];
NSLog(#"%#",idd);
[webview loadHTMLString:idd baseURL:nil];
NSLog(#"%#",thiss);
Ok so from your comment the only problem you have, is that only the first row is shown. That is because you only add the first row to the html outside of the for loop:
for (int i=0; i<3; i++) {
thiss= [NSString stringWithFormat:#"<tr><td>Data1</td><td> %#</td><td>Data1</td><td>Data1</td><td>Data1</td></tr>",[array objectAtIndex:i]];
[myArray addObject:thiss];
}
thiss =[embedHtml stringByAppendingString:[myArray objectAtIndex:0]];
not sure for what you use the array. but adding the html directly to the string inside the for loop solves your problem: (cleaned code)
// creating values with shorter literal syntax
NSArray *values = #[#"1",#"2",#"3"];
// create mutable string
NSMutableString *embedHTML = [#"<html><head><title>First</title><style>table , td, table , tr, th{border:1px solid #333333;padding:2px;}</style></head><body><table ><tr><th>Col1</th><th>Col2</th><th>Col3</th><th>Col4</th><th>Col5</th></tr>" mutableCopy];
for (int i=0; i<3; i++) {
// create row html and append it to mutable embedHTML
NSString *rowHTML = [NSString stringWithFormat:#"<tr><td>Data1</td><td> %#</td><td>Data1</td><td>Data1</td><td>Data1</td></tr>", values[i]];
[embedHTML appendString:rowHTML];
}
// finish html
[embedHTML appendString:#"</table></body></html>"];
NSLog(#"%#", embedHTML);
[webview loadHTMLString:embedHTML baseURL:nil];
Also note, that if you have a fixed width values array, using for in loop is much simpler, understandable and maintainable than using for:
for (NSString *value in values) {
// create row html and append it to mutable embedHTML
NSString *rowHTML = [NSString stringWithFormat:#"<tr><td>Data1</td><td> %#</td><td>Data1</td><td>Data1</td><td>Data1</td></tr>", value];
[embedHTML appendString:rowHTML];
}
therefore there is no redundancy and as soon as you extend the values array your code keeps working as expected.

export data in html table format in ios7 and make email body

I am new in iphone application development. In my application i am using two different NSMutable array's. Both have dictionary with 4 fields like name, address etc at each index. Now my problem is I want to export that data in HTML table format and make email body. So please, can any one help me.
thank you
For example items are:
NSMutableArray *arrItem = [NSMutableArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"sam",#"name",#"london",#"address",nil], nil];
Now create html string like this :
NSString *strHTML = #"<!DOCTYPE html>"
#"<html><body>"
#"<table border=\"1\" style=\"width:300px\">"; //change width according to your requirement
for (NSDictionary *dict in arrItem) {
NSString *strName = [dict objectForKey:#"name"];
NSString *strAddress = [dict objectForKey:#"address"];
strHTML = [strHTML stringByAppendingString:#"<tr>"];
//add table column value
strHTML = [strHTML stringByAppendingString:[NSString stringWithFormat:#"<td>%#</td>",strName]];
strHTML = [strHTML stringByAppendingString:[NSString stringWithFormat:#"<td>%#</td>",strAddress]];
strHTML = [strHTML stringByAppendingString:#"</tr>"];
}
strHTML = [strHTML stringByAppendingString:#"</table>"
#"</body>"
#"</html>"];
Use hmtl string in MailcompserViewController :
[controller setMessageBody:strHTML isHTML:YES];
EDIT : formatted
MailcompserViewController *controller = [[MailcompserViewController alloc] init];//Allocating mailComposer
NSString *eMailBody=#""; //Value for row
for (int i=0; i<[arrMailList count]; i++) { //Get all the row value
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
MailData *data = [arrMailList objectAtIndex:i]; //Get array value in NSObject class
NSDate *date = [dateFormat dateFromString:data.date];
NSDateFormatter *dateFormat1 = [[NSDateFormatter alloc] init];
[dateFormat1 setDateFormat:#"EEEE, dd MMMM yyyy"]; //Date NSDateFormatter
NSString *strDate = [dateFormat1 stringFromDate:date];
NSString *numbers = [data.setName stringByTrimmingCharactersInSet:[NSCharacterSet letterCharacterSet]];
eMailBody = [eMailBody stringByAppendingFormat:#"<tr><td width=\"200px\">%#</td><td >%#</td><td >%#</td><td >%#</td><td>%#</td><td >%#</td></tr>",strDate,data.Name,data.email,data.address,data.phoneNumber];//Create row
}
NSString *html = [NSString stringWithFormat:#"<html><style>body{font-family:Helvetica;font-size:14px;}th{fontcolor:#ffffff;font-size:16px;font-weight:BOLD;}</style><body><table cellpadding=5px border=1px bordercolor=#000000><tr bgcolor=#cccccc><th width=200>Date</th><th>Workout Name</th><th>Excercise Name</th><th>Set</th><th>Weight</th><th>Reps</th>%#</table></body></html>",eMailBody]; //Add row in table view
[controller setMessageBody:html isHTML:YES];
[self presentViewController:controller animated:YES completion:nil];
var str = "\n"
str=str.stringByAppendingString("<tr><th>")
str=str.stringByAppendingString("Task")
str=str.stringByAppendingString("</th>")
str=str.stringByAppendingString("<th>")
str=str.stringByAppendingString("SpareParts")
str=str.stringByAppendingString("</th>")
str=str.stringByAppendingString("<th>")
str=str.stringByAppendingString("Labour")
str=str.stringByAppendingString("</th></tr>\n")
var i:Int=0
for i=0;i<carImageList.count;i++
{
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString(carImageList[i] as! String)
str=str.stringByAppendingString("</td></tr>\n")
}
//SubTotal
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString("Sub Total")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString("100")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td>")
str=str.stringByAppendingString("100")
str=str.stringByAppendingString("</td></tr>\n")
//Total
str=str.stringByAppendingString("<tr><td>")
str=str.stringByAppendingString("Total")
str=str.stringByAppendingString("</td>")
str=str.stringByAppendingString("<td colSpan='2'>")
str=str.stringByAppendingString("300")
str=str.stringByAppendingString("</td></tr>\n")
str=str.stringByAppendingString("</table></body></html>\n")
NSLog("TEST %#",str)
mailComposerVC.setMessageBody(str, isHTML: true)

Searching for keywords in HTML

The iOS app I'm writing displays an HTML page, and I would like to add a search feature where the user can search for instances of a keyword and highlight them.
What's the best way to do this?
NSString *filePath = PATH_OF_HTML_FILE;
NSError *err = nil;
NSString *pageHTML = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&err];
if(err)
{
pageHTML = [NSString stringWithContentsOfFile:filePath encoding:NSASCIIStringEncoding error:&err];
}
if([searchTxtField.text length])
{
NSRange range1 = [pageHTML rangeOfString:searchTxtField.text options:NSCaseInsensitiveSearch];
if(range1.location != NSNotFound)
{
NSString *highlightedString = [pageHTML substringWithRange:range1];
pageHTML = [pageHTML stringByReplacingOccurrencesOfString:highlightedString withString:[NSString stringWithFormat:#"<span style=\"background-color:yellow; color:red;\">%#</span>",highlightedString] options:NSCaseInsensitiveSearch range:NSMakeRange(0, [pageHTML length]) ];
[webView loadHTMLString:pageHTML baseURL:[NSURL fileURLWithPath:filePath]];
}
}

MFMailComposeViewController csv attachment not being attached, but showing inline instead

I am having a problem with sending csv attachments via MFMailComposeViewController.
Sometimes they come through just fine, but for other users they don't come through as attachments, but rather as text inline in the email (with <br/> instead of line returns.) It's very strange. Anybody know what I'm doing wrong?
Here is a snippet of my code:
MFMailComposeViewController *mailComposeViewController = [[MFMailComposeViewController alloc] init];
mailComposeViewController.mailComposeDelegate = self;
NSString *csv = #"foo,bar,blah,hello";
NSData *csvData = [csv dataUsingEncoding:NSUTF8StringEncoding];
[mailComposeViewController addAttachmentData:csvData mimeType:#"text/csv" fileName:#"testing.csv"];
[mailComposeViewController setSubject:#"testing sending csv attachment"];
[mailComposeViewController setMessageBody:#"csv file should be attached" isHTML:NO];
[self presentModalViewController:mailComposeViewController animated:YES];
-(IBAction)btnPressed:(id)sender {
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *docDir = [arrayPaths objectAtIndex:0];
NSString *Path = [docDir stringByAppendingString:#"/CSVFile.csv"];
NSData *csvData = [NSData dataWithContentsOfFile:Path];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"For csv file..."];
[controller setMessageBody:#"...csv file is hear.." isHTML:NO];
[controller addAttachmentData:csvData mimeType:#"text/csv" fileName:#"CSVFile.csv"];
[self presentModalViewController:controller animated:YES];
[controller release];
}
Hi I put sample code for Creating CSV file and attach it with mail but make sure you have to add MessageUI.Framework and import its related header "MessageUI/MessageUI.h"
"MessageUI/MFMailComposeViewController.h" and deligate "MFMailComposeViewControllerDelegate"...I hope this wl useful for others
- (void)viewDidLoad {
arrCsv=[[NSArray alloc]initWithObjects:#"Hello",#"Hi",#"traun",#"fine",nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:#"%#/try.csv", documentsDirectory];
[[arrCsv componentsJoinedByString:#","] writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
-(ibAction)btnMail {
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *docDir = [arrayPaths objectAtIndex:0];
NSString *Path = [docDir stringByAppendingString:#"/CSVFile.csv"];
NSData *csvData = [NSData dataWithContentsOfFile:Path];
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"For csv file..."];
[controller setMessageBody:#"...csv file is hear.." isHTML:NO];
[controller addAttachmentData:csvData mimeType:#"text/csv" fileName:#"CSVFile.csv"];
[self presentModalViewController:controller animated:YES];
[controller release];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{ message.hidden = NO;
switch (result)
{
case MFMailComposeResultCancelled:
message.text = #"Result: canceled";
break;
case MFMailComposeResultSaved:
message.text = #"Result: saved";
break;
case MFMailComposeResultSent:
message.text = #"Result: sent";
break;
case MFMailComposeResultFailed:
message.text = #"Result: failed";
break;
default:
message.text = #"Result: not sent";
break;
}
[self dismissModalViewControllerAnimated:YES];
}
set the mime type as "application/octet-stream" and that should do the trick to remove inline attachments (I still named the extension of my file i.e. pdf)
I believe the second parameter to setMessageBody:isHTML: must be YES for attachments to not show up inline.
Even if you set isHTML param to YES, your message body can be sent as plain/text if the message body can be represented as such. And attachments in plain/text messages are not always recognized correctly by some email clients (Outlook).
In my case adding a link in the message body helped. Formatting text as bold with HTML tags works too. Tricky!
Tested on iPod 1G 3.1.3.
This may not be the case here, but one thing to watch out for is that:
[NSString dataUsingEncoding:]
returns a valid but empty NSData object if the conversion to the specified encoding is not possible. Better to use the full version:
[NSString dataUsingEncoding: s allowLossyConversion: YES]
Or check the length of the returned data. It appears that zero-length data attachments are trimmed somewhere in the mail process.