Hapus Tag HTML dari NSString di iPhone

106

Ada beberapa cara berbeda untuk menghapus HTML tagsdari NSStringdalam Cocoa.

Salah satu caranya adalah dengan membuat string menjadi NSAttributedStringdan kemudian mengambil teks yang dirender.

Cara lain adalah dengan menggunakan NSXMLDocument's- objectByApplyingXSLTStringmetode untuk menerapkan XSLTtransformasi yang melakukannya.

Sayangnya, iPhone tidak mendukung NSAttributedStringatau NSXMLDocument. Ada terlalu banyak kasus tepi dan HTMLdokumen rusak sehingga saya merasa nyaman menggunakan regex atau NSScanner. Apakah ada yang punya solusi untuk ini?

Salah satu saran adalah hanya mencari karakter tag pembuka dan penutup, metode ini tidak akan berfungsi kecuali untuk kasus yang sangat sepele.

Misalnya, kasus ini (dari bab Buku Resep Perl tentang subjek yang sama) akan merusak metode ini:

<IMG SRC = "foo.gif" ALT = "A > B">

<!-- <A comment> -->

<script>if (a<b && a>c)</script>

<![INCLUDE CDATA [ >>>>>>>>>>>> ]]>
lfalin
sumber
Anda dapat menambahkan sedikit logika untuk memperhitungkan tanda kutip dan apostrof ... CDATA akan membutuhkan sedikit lebih banyak pekerjaan, tetapi inti dari HTML adalah bahwa tag yang tidak dikenal dapat diabaikan oleh parser; jika Anda memperlakukan SEMUA tag sebagai tidak dikenal, maka Anda hanya perlu mendapatkan teks mentah.
Ben Gottlieb
Saya ingin mengomentari bahwa ekspresi reguler yang baik (tapi dasar) pasti tidak akan merusak contoh Anda. Tentu tidak jika Anda dapat menjamin XHTML dalam format yang baik. Saya tahu bahwa Anda mengatakan Anda tidak bisa, tetapi saya heran mengapa ;-)
Jake
1
Ada jawaban yang bagus untuk pertanyaan ini. Ratakan HTML menggunakan Objective c
vipintj
Sayangnya, penggunaan NSScanner sangat lambat.
steipete
Yang lebih disayangkan, contoh NSScanner tertaut hanya berfungsi untuk html sepele. Itu gagal untuk setiap kasus uji yang saya sebutkan di posting saya.
lfalin

Jawaban:

309

Solusi cepat dan "kotor" (menghapus segala sesuatu antara <dan>), bekerja dengan iOS> = 3.2:

-(NSString *) stringByStrippingHTML {
  NSRange r;
  NSString *s = [[self copy] autorelease];
  while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
    s = [s stringByReplacingCharactersInRange:r withString:@""];
  return s;
}

Saya telah menyatakan ini sebagai kategori os NSString.

m.kocikowski
sumber
4
@James Untuk menggunakan metode yang diposting dalam solusi. Anda harus membuat kategori untuk NSString. Cari "Kategori Objective-C" di Google. Kemudian Anda menambahkan metode itu di file m, dan prototipe di file h. Ketika semuanya sudah diatur, untuk menggunakannya yang harus Anda lakukan adalah memiliki objek string (Contoh: NSString * myString = ...) dan Anda memanggil metode itu pada objek string Anda (NSString * strippedString = [myString stringByStrippingHTML]; ).
Roberto
3
+1 Sangat berguna untuk ekspresi reguler, tetapi sayangnya tidak mencakup banyak kasus.
matm
3
Cepat dan kotor memang .... Fungsi ini menyebabkan kebocoran memori yang besar di aplikasi saya ... Nah, dalam pembelaannya, saya menggunakan data dalam jumlah besar ....
EZFrag
5
Di Aplikasi saya, solusi ini menyebabkan masalah kinerja. Saya beralih ke solusi dengan NSScanner, bukan NSRegularExpressionSearch. Sekarang masalah kinerja sudah hilang
carmen_munich
2
Ini sangat memakan memori dan waktu. Gunakan ini hanya dengan sedikit html!
ullstrm
29

NSStringKategori ini menggunakan NSXMLParseruntuk secara akurat menghapus HTMLtag apa pun dari NSString. Ini adalah satu .mdan .hfile yang dapat dimasukkan ke dalam proyek Anda dengan mudah.

https://gist.github.com/leighmcculloch/1202238

Anda kemudian menghapus htmldengan melakukan hal berikut:

Impor tajuk:

#import "NSString_stripHtml.h"

Dan kemudian panggil stripHtml:

NSString* mystring = @"<b>Hello</b> World!!";
NSString* stripped = [mystring stripHtml];
// stripped will be = Hello World!!

Ini juga bekerja dengan cacat HTMLyang secara teknis tidak XML.

Leigh McCulloch
sumber
3
Meskipun ekspresi reguler (seperti yang dikatakan oleh m.kocikowski) cepat dan kotor, ini lebih kuat. Contoh string: @ "Tes saya <span font = \" font> name \ "> string html". Jawaban ini mengembalikan: String html pengujian saya. Ekspresi reguler mengembalikan: Nama pengujian saya "> string html. Meskipun ini tidak umum, itu hanya lebih kuat.
DonnaLea
1
Kecuali jika Anda memiliki string seperti "S&P 500", itu akan menghapus semuanya setelah ampersand dan hanya mengembalikan string "S".
Joshua Gross
11
UITextView *textview= [[UITextView alloc]initWithFrame:CGRectMake(10, 130, 250, 170)];
NSString *str = @"This is <font color='red'>simple</font>";
[textview setValue:str forKey:@"contentToHTMLString"];
textview.textAlignment = NSTextAlignmentLeft;
textview.editable = NO;
textview.font = [UIFont fontWithName:@"vardana" size:20.0];
[UIView addSubview:textview];

bekerja dengan baik untuk saya

MANCHIKANTI KRISHNAKISHORE
sumber
1
Saya mendapat masalah pengkodean dengan solusi ini
KIDdAe
Mungkin solusi terbaik, tetapi tidak berguna untuk UILabel :-(
Zeb
9

Anda bisa menggunakan seperti di bawah ini

-(void)myMethod
 {

 NSString* htmlStr = @"<some>html</string>";
 NSString* strWithoutFormatting = [self stringByStrippingHTML:htmlStr];

 }

 -(NSString *)stringByStrippingHTML:(NSString*)str
 {
   NSRange r;
   while ((r = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location     != NSNotFound)
  {
     str = [str stringByReplacingCharactersInRange:r withString:@""];
 }
  return str;
 }
Kirtikumar A.
sumber
8

Gunakan ini

NSString *myregex = @"<[^>]*>"; //regex to remove any html tag

NSString *htmlString = @"<html>bla bla</html>";
NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:@""];

jangan lupa untuk memasukkan ini ke dalam kode Anda: #import "RegexKitLite.h" di sini adalah tautan untuk mengunduh API ini: http://regexkit.sourceforge.net/#Downloads

Mohamed AHDIDOU
sumber
7

Lihat NSXMLParser. Ini adalah pengurai gaya SAX. Anda harus dapat menggunakannya untuk mendeteksi tag atau elemen lain yang tidak diinginkan dalam dokumen XML dan mengabaikannya, hanya menangkap teks murni.

Colin Barrett
sumber
6

Berikut solusi yang lebih efisien daripada jawaban yang diterima:

- (NSString*)hp_stringByRemovingTags
{
    static NSRegularExpression *regex = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        regex = [NSRegularExpression regularExpressionWithPattern:@"<[^>]+>" options:kNilOptions error:nil];
    });

    // Use reverse enumerator to delete characters without affecting indexes
    NSArray *matches =[regex matchesInString:self options:kNilOptions range:NSMakeRange(0, self.length)];
    NSEnumerator *enumerator = matches.reverseObjectEnumerator;

    NSTextCheckingResult *match = nil;
    NSMutableString *modifiedString = self.mutableCopy;
    while ((match = [enumerator nextObject]))
    {
        [modifiedString deleteCharactersInRange:match.range];
    }
    return modifiedString;
}

NSStringKategori di atas menggunakan ekspresi reguler untuk menemukan semua tag yang cocok, membuat salinan dari string asli dan akhirnya menghapus semua tag di tempatnya dengan mengulanginya dalam urutan terbalik. Lebih efisien karena:

  • Ekspresi reguler hanya dimulai sekali.
  • Salinan tunggal dari string asli digunakan.

Ini berkinerja cukup baik bagi saya tetapi penggunaan solusi NSScannermungkin lebih efisien.

Seperti jawaban yang diterima, solusi ini tidak menangani semua kasus perbatasan yang diminta oleh @lfalin. Itu akan membutuhkan penguraian yang jauh lebih mahal yang kemungkinan besar tidak diperlukan oleh kasus penggunaan rata-rata.

hpique
sumber
5

Tanpa loop (setidaknya di pihak kami):

- (NSString *)removeHTML {

    static NSRegularExpression *regexp;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        regexp = [NSRegularExpression regularExpressionWithPattern:@"<[^>]+>" options:kNilOptions error:nil];
    });

    return [regexp stringByReplacingMatchesInString:self
                                            options:kNilOptions
                                              range:NSMakeRange(0, self.length)
                                       withTemplate:@""];
}
Rémy
sumber
Ini harus menjadi jawaban yang diterima. Yang saat ini sangat boros.
Adlai Holler
5
NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];
Pavan Sisode
sumber
Ketika kita memiliki data meta dengan tag HTML dan ingin menerapkan tag itu, saat itu kita harus menerapkan kode di atas untuk mencapai keluaran yang diinginkan.
Pavan Sisode
4
#import "RegexKitLite.h"

string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""]
Jim Liu
sumber
2
HTML bukanlah bahasa biasa, jadi Anda tidak boleh mencoba mengurai / menghapusnya dengan ekspresi reguler. stackoverflow.com/questions/1732348/…
csaunders
3

Saya telah memperpanjang jawabannya dengan m.kocikowski dan mencoba membuatnya sedikit lebih efisien dengan menggunakan NSMutableString. Saya juga telah menyusunnya untuk digunakan dalam kelas Utils statis (saya tahu Kategori mungkin adalah desain terbaik), dan menghapus autorelease sehingga dikompilasi dalam proyek ARC.

Disertakan di sini jika ada yang menganggapnya berguna.

.h

+ (NSString *)stringByStrippingHTML:(NSString *)inputString;

.m

+ (NSString *)stringByStrippingHTML:(NSString *)inputString 
{
  NSMutableString *outString;

  if (inputString)
  {
    outString = [[NSMutableString alloc] initWithString:inputString];

    if ([inputString length] > 0)
    {
      NSRange r;

      while ((r = [outString rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
      {
        [outString deleteCharactersInRange:r];
      }      
    }
  }

  return outString; 
}
Dan J
sumber
Metode ini berguna tetapi, jika saya perlu non-strip beberapa tag seperti tautan <a> yang saya dapat memperbarui metode ini untuk memenuhi ini
wod
@wod maka cukup ubah regex menjadi <(?>/?)(?!a).+?>ini akan menghapus semua tag kecuali tag pembuka <a> dan penutup </a>.
Ashoor
3

Jika Anda ingin mendapatkan konten tanpa tag html dari halaman web (dokumen HTML), gunakan kode ini di dalam metode UIWebViewDidfinishLoading delegasi .

  NSString *myText = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
Biranchi
sumber
Situs sedang digantikan oleh apa pun ... yang tidak diinginkan.
Nishant
2

Saya akan membayangkan cara teraman hanya dengan mengurai <> s, bukan? Ulangi seluruh string, dan salin semua yang tidak diapit <> s ke string baru.

Ben Gottlieb
sumber
2

Ini adalah modernisasi jawaban m.kocikowski yang menghilangkan spasi:

@implementation NSString (StripXMLTags)

- (NSString *)stripXMLTags
{
    NSRange r;
    NSString *s = [self copy];
    while ((r = [s rangeOfString:@"<[^>]+>\\s*" options:NSRegularExpressionSearch]).location != NSNotFound)
        s = [s stringByReplacingCharactersInRange:r withString:@""];
    return s;
}

@end
digipeople
sumber
2

berikut ini adalah jawaban yang diterima, tetapi alih-alih kategori, ini adalah metode pembantu sederhana dengan string yang dilewatkan ke dalamnya. (terima kasih m.kocikowski)

-(NSString *) stringByStrippingHTML:(NSString*)originalString {
    NSRange r;
    NSString *s = [originalString copy];
    while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
        s = [s stringByReplacingCharactersInRange:r withString:@""];
    return s;
}
tmr
sumber
2

Berikut versi cepatnya:

func stripHTMLFromString(string: String) -> String {
  var copy = string
  while let range = copy.rangeOfString("<[^>]+>", options: .RegularExpressionSearch) {
    copy = copy.stringByReplacingCharactersInRange(range, withString: "")
  }
  copy = copy.stringByReplacingOccurrencesOfString("&nbsp;", withString: " ")
  copy = copy.stringByReplacingOccurrencesOfString("&amp;", withString: "&")
  return copy
}
JohnVanDijk
sumber
Man, stringByReplacingOccurrencesOfStringu gunakan di luar siklus adalah encoding persen dan harus diperbaiki melalui cara yang benar.
Vyachaslav Gerchicov
0

Jika Anda ingin menggunakan kerangka kerja Three20 , ia memiliki kategori di NSString yang menambahkan metode stringByRemovingHTMLTags. Lihat NSStringAdditions.h di subproyek Three20Core.

jarnoan.dll
sumber
26
Demi Tuhan, jangan gunakan Three20 untuk apa pun. Kerangka komentar paling membengkak dan buruk yang pernah ada.
kompozer
0

Memperluas ini lebih banyak dari jawaban m.kocikowski dan Dan J dengan lebih banyak penjelasan untuk pemula

1 # Pertama Anda harus membuat tujuan-kategori-c untuk membuat kode dapat digunakan di kelas manapun.

.h

@interface NSString (NAME_OF_CATEGORY)

- (NSString *)stringByStrippingHTML;

@end

.m

@implementation NSString (NAME_OF_CATEGORY)

- (NSString *)stringByStrippingHTML
{
NSMutableString *outString;
NSString *inputString = self;

if (inputString)
{
    outString = [[NSMutableString alloc] initWithString:inputString];

    if ([inputString length] > 0)
    {
        NSRange r;

        while ((r = [outString rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
        {
            [outString deleteCharactersInRange:r];
        }
    }
}

return outString;
}

@end

2 # Kemudian cukup impor file .h dari kelas kategori yang baru saja Anda buat misalnya

#import "NSString+NAME_OF_CATEGORY.h"

3 # Memanggil Metode.

NSString* sub = [result stringByStrippingHTML];
NSLog(@"%@", sub);

Hasilnya adalah NSString yang ingin saya hapus tagnya.

Ashoor
sumber
0

Saya telah mengikuti jawaban yang diterima oleh m.kocikowski dan dimodifikasi sedikit untuk menggunakan autoreleasepool untuk membersihkan semua string sementara yang dibuat oleh stringByReplacingCharactersInRange

Dalam komentar untuk metode ini dinyatakan, / * Ganti karakter dalam rentang dengan string yang ditentukan, mengembalikan string baru. * /

Jadi, bergantung pada panjang XML Anda, Anda mungkin membuat tumpukan besar string autorelease baru yang tidak dibersihkan hingga akhir @autoreleasepool berikutnya. Jika Anda tidak yakin kapan itu mungkin terjadi atau jika tindakan pengguna dapat berulang kali memicu banyak panggilan ke metode ini sebelumnya, Anda dapat membungkusnya dengan @autoreleasepool. Ini bahkan dapat disarangkan dan digunakan dalam loop jika memungkinkan.

Referensi Apple di @autoreleasepool menyatakan ini ... "Jika Anda menulis loop yang membuat banyak objek sementara. Anda dapat menggunakan blok kumpulan autorelease di dalam loop untuk membuang objek tersebut sebelum iterasi berikutnya. Menggunakan blok kumpulan autorelease di loop membantu mengurangi jejak memori maksimum aplikasi. " Saya belum menggunakannya dalam loop, tetapi setidaknya metode ini membersihkan dirinya sendiri sekarang.

- (NSString *) stringByStrippingHTML {
    NSString *retVal;
    @autoreleasepool {
        NSRange r;
        NSString *s = [[self copy] autorelease];
        while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) {
            s = [s stringByReplacingCharactersInRange:r withString:@""];
        }
        retVal = [s copy];
    } 
    // pool is drained, release s and all temp 
    // strings created by stringByReplacingCharactersInRange
    return retVal;
}
jcpennypincher.dll
sumber
0

Satu cara lain:

Antarmuka:

-(NSString *) stringByStrippingHTML:(NSString*)inputString;

Penerapan

(NSString *) stringByStrippingHTML:(NSString*)inputString
{ 
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[inputString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil];
NSString *str= [attrString string]; 

//you can add here replacements as your needs:
    [str stringByReplacingOccurrencesOfString:@"[" withString:@""];
    [str stringByReplacingOccurrencesOfString:@"]" withString:@""];
    [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];

    return str;
}

Realisasi

cell.exampleClass.text = [self stringByStrippingHTML:[exampleJSONParsingArray valueForKey: @"key"]];

atau sederhana

NSString *myClearStr = [self stringByStrippingHTML:rudeStr];

Nik Kov
sumber
metode ini menghapus tag html. tetapi saya ingin mengurai string html. apa yang harus dilakukan
Krutarth Patel
menghemat waktu saya. solusi yang bagus
Krutarth Patel
0

Jawaban terbaru untuk @ m.kocikowski yang berfungsi pada versi iOS terbaru.

-(NSString *) stringByStrippingHTMLFromString:(NSString *)str {
NSRange range;
while ((range = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
    str = [str stringByReplacingCharactersInRange:range withString:@""];
return str;

}

Ahmed Awad
sumber
-3

Berikut adalah entri blog yang membahas beberapa perpustakaan yang tersedia untuk menghapus HTML http://sugarmaplesoftware.com/25/strip-html-tags/ Perhatikan komentar di mana solusi lain ditawarkan.

micco
sumber
Ini adalah kumpulan komentar persis yang saya tautkan dalam pertanyaan saya sebagai contoh tentang apa yang tidak akan berhasil.
lfalin