2009-06-09 36 views
10

Tôi đang tìm cách phân tích nhanh các thẻ HTML ra khỏi chuỗi Coldfusion. Chúng tôi đang kéo một nguồn cấp dữ liệu RSS, có khả năng có bất kỳ thứ gì trong đó. Sau đó chúng tôi đang thực hiện một số thao tác thông tin và sau đó nhổ nó ra một nơi khác. Hiện tại chúng tôi đang làm điều này với một biểu thức chính quy. Có cách nào tốt hơn để làm điều này?Tôi làm cách nào để xóa các thẻ HTML khỏi chuỗi ColdFusion?

<cfloop from="1" to="#ArrayLen(myFeed.item)#" index="i"> 
    <cfset myFeed.item[i].description.value = 
    REReplaceNoCase(myFeed.item[i].description.value, '<(.|\n)*?>', '', 'ALL')> 
</cfloop> 

Chúng tôi đang sử dụng ColdFusion 8.

Trả lời

14

Disclaimer Tôi là một người ủng hộ quyết liệt của việc sử dụng một cú pháp thích hợp (thay vì regex) để phân tích HTML. Tuy nhiên, câu hỏi này không phải là về việc phân tích cú pháp HTML, nhưng về việc phá hủy nó. Đối với tất cả các tác vụ vượt xa điều đó, hãy sử dụng trình phân tích cú pháp.


Tôi nghĩ rằng regex của bạn là tốt. Miễn là không có gì hơn xóa tất cả các thẻ HTML khỏi đầu vào, sử dụng regex như của bạn là an toàn.

Bất cứ điều gì khác có lẽ sẽ là rắc rối hơn nó có giá trị, nhưng bạn có thể viết một hàm nhỏ mà vòng qua các chuỗi char-by-char một lần và loại bỏ tất cả mọi thứ đó là trong dấu ngoặc thẻ — ví dụ:

  • switch trên cơ sở "inTag" cờ ngay khi bạn gặp một "<" nhân vật,
  • chuyển đổi nó đi ngay sau khi bạn gặp phải ">"
  • ký tự sao chép vào chuỗi sản lượng chừng nào cờ tắt
  • để thực hiện, sử dụng đối tượng Java StringBuilder thay vì chuỗi nối

Đối với phần có nhu cầu cao của ứng dụng, điều này có thể nhanh hơn regex. Nhưng regex là sạch sẽ và có lẽ đủ nhanh.

lẽ regex sửa đổi này có một số lợi thế cho bạn:

<[^>]*(?:>|$) 
  • bắt thẻ không khép kín ở phần cuối của chuỗi
  • [^>]* là tốt hơn so với (.|\n)

Việc sử dụng REReplaceNoCase() là không cần thiết khi không có chữ cái thực trong mẫu. Đối sánh regex phân biệt chữ hoa chữ thường chậm hơn so với trường hợp nhạy cảm.

+0

Tôi đã tìm thấy <[^>] *> làm regex có thể sửa đổi. Lợi ích gì trong nửa thứ hai của bạn cung cấp? – Jason

+0

Như tôi đã nói: Nó bắt các thẻ không được khép kín ở cuối chuỗi. "(?:> | $)" đọc dưới dạng "dấu ngoặc đơn đóng hoặc kết thúc chuỗi". Phần còn lại của regex tương đương với thay thế bạn đã tìm thấy. "[^>] *" thường được đề xuất nhiều hơn "(. | \ n) *?", bởi vì nó rõ ràng hơn và nhanh hơn. – Tomalak

+1

Tôi khuyên bạn nên làm thẻ thứ hai để thay thế bằng >, vì bạn có thể có một số thức ăn thừa. – Kip

2

Cách tốt nhất thường là ép buộc < đến &lt;> đến &gt;. Bằng cách này, bạn không đưa ra giả định về bản chất của thông điệp. Ai đó có thể đang nói về <tags> hoặc cố gắng là <<expressive>> hoặc mô tả một tổ hợp phím <Ctrl>+C hoặc sử dụng toán học 1 <x> 3.Ngay cả smilies có thể kích hoạt các regex <8P X>

<cfloop from="1" to="#ArrayLen(myFeed.item)#" index="i"> 
    <cfset myFeed.item[i].description.value = ReplaceList(myFeed.item[i].description.value, '<,>', '&lt;,&gt;')> 
</cfloop> 
+1

@SpliFF: Về "Ngay cả mặt cười cũng có thể kích hoạt regex" - không, họ không thể. Chúng sẽ được mã hóa thành "< 8P". – Tomalak

+0

Vâng, anh ấy nói rằng dữ liệu của anh ấy đến từ một nguồn cấp dữ liệu RSS. nếu nguồn cấp dữ liệu là thích hợp, chỉ số < and > trống sẽ là từ các thẻ, những người khác sẽ là < và >.Nó là khá có thể nguồn cấp dữ liệu có thể không đúng định dạng, nhưng đó sẽ là vấn đề của nhà cung cấp (mà có lẽ sẽ mess lên bất kỳ phân tích cú pháp nguồn cấp dữ liệu). – Kip

+0

]]> không hợp lệ trong mô tả nguồn cấp dữ liệu RSS? –

7

HTML không phải là một ngôn ngữ thông thường, vì vậy sử dụng biểu thức chính quy trên (không kiểm soát được) HTML là cái gì đó nên được thực hiện một cách cẩn thận tuyệt vời (nếu có).

Xem xét, ví dụ, sau đây hợp lệ phân đoạn của HTML:

<img src="boat.jpg" alt="a boat" title="My boat is > everything! I <3 my boat!"> 

Bạn sẽ lưu ý như thế nào highlighter cú pháp là nghẹt thở trên đó - như sẽ regex hiện đã được cung cấp.

Trừ khi bạn có thể là nhất định rằng chuỗi bạn đang xử lý sẽ không chứa mã HTML tương tự như trên, bạn nên tránh đưa ra giả định/thỏa hiệp, một tuyến đường regex đơn/tinh khiết sẽ buộc bạn phải làm.

(Lưu ý:. Vấn đề tương tự áp dụng cho phương pháp đề nghị char-by-char quá)


Để giải quyết vấn đề của bạn, bạn nên sử dụng một phân tích cú pháp DOM để phân tích chuỗi của bạn thành một đối tượng HTML, looping thông qua từng phần tử và chuyển đổi thành văn bản.

Nếu bạn có XHTML hợp lệ thì bạn có thể sử dụng số XmlParse() của CF để tạo đối tượng mà bạn có thể lặp lại. Nếu nó có thể không phải là XML HTML thì không có tùy chọn tích hợp với CF8, vì vậy bạn sẽ phải điều tra các tùy chọn trong Java/etc.

+0

ah, lập trình thuyền :) – jinglesthula

3

tôi sử dụng này:

REReplaceNoCase(text, "<[^[:space:]][^>]*>", "", "ALL"); 

99% các trường hợp nó hoạt động tốt.

0
<cfset a = "<b><font color = 'red'>(PCB) <1 ppm </font></b>"> 

<cfset b = REReplaceNoCase(a, "<[^><]*>", '', 'ALL')> 

<cfdump var="#b#"> 

đầu ra b = "(PCB) < 1 ppm"

Các Regex "< [^> <] *>" sẽ xóa tất cả các thẻ và các nhân vật trong những thẻ và sẽ không loại bỏ thẻ đơn như < hoặc> có thể được sử dụng dưới hoặc lớn hơn ký hiệu trong chuỗi

Các vấn đề liên quan