2011-10-04 17 views
15

Tôi có một cơ sở dữ liệu lớn chứa các bản ghi có các thẻ <a> trong đó và tôi muốn xóa chúng. Tất nhiên có phương pháp mà tôi tạo ra một kịch bản PHP mà chọn tất cả, sử dụng strip_tags và cập nhật cơ sở dữ liệu, nhưng điều này mất một thời gian dài. Vậy làm thế nào tôi có thể làm điều này với một truy vấn MySQL đơn giản (hoặc phức tạp)?Truy vấn MySQL tương đương với PHP strip_tags là gì?

Trả lời

4

Tôi không tin rằng có bất kỳ cách hiệu quả để làm điều này trong MySQL một mình.

MySQL có chức năng REPLACE(), nhưng nó chỉ có thể thay thế chuỗi không đổi, không phải mẫu. Bạn có thể có thể viết một chức năng được lưu trữ MySQL để tìm kiếm và thay thế các thẻ, nhưng tại thời điểm đó, bạn có thể tốt hơn khi viết một kịch bản PHP để thực hiện công việc. Có thể không phải là khá nhanh, nhưng có thể viết nhanh hơn.

+0

có lẽ bạn là đúng :( – faq

-1

REPLACE() hoạt động khá tốt.

Cách tiếp cận tinh tế:

REPLACE(REPLACE(node.body,'<p>',''),'</p>','') as `post_content` 

... và không quá tinh tế: (Chuyển đổi chuỗi thành sên)

LOWER(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(TRIM(node.title), ':', ''), 'é', 'e'), ')', ''), '(', ''), ',', ''), '\\', ''), '\/', ''), '\"', ''), '?', ''), '\'', ''), '&', ''), '!', ''), '.', ''), '–', ''), ' ', '-'), '--', '-'), '--', '-'), '’', '')) as `post_name` 
16

Ở đây bạn đi:

CREATE FUNCTION `strip_tags`($str text) RETURNS text 
BEGIN 
    DECLARE $start, $end INT DEFAULT 1; 
    LOOP 
     SET $start = LOCATE("<", $str, $start); 
     IF (!$start) THEN RETURN $str; END IF; 
     SET $end = LOCATE(">", $str, $start); 
     IF (!$end) THEN SET $end = $start; END IF; 
     SET $str = INSERT($str, $start, $end - $start + 1, ""); 
    END LOOP; 
END; 

tôi đã thực hiện chắc chắn nó loại bỏ dấu ngoặc mở không khớp vì chúng nguy hiểm, mặc dù nó bỏ qua bất kỳ dấu ngoặc đóng chưa được ghép nối nào vì chúng vô hại.

mysql> select strip_tags('<span>hel<b>lo <a href="world">wo<>rld</a> <<x>again<.'); 
+----------------------------------------------------------------------+ 
| strip_tags('<span>hel<b>lo <a href="world">wo<>rld</a> <<x>again<.') | 
+----------------------------------------------------------------------+ 
| hello world again.             | 
+----------------------------------------------------------------------+ 
1 row in set 
+0

didnt làm việc cho tôi; MySQL cho biết: Tài liệu # 1064 - Bạn có một lỗi trong cú pháp SQL của bạn; kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn cho đúng cú pháp sử dụng gần '' tại dòng 3 – mahen3d

+4

'delimiter // CREATE strip_tags CHỨC NĂNG ($ str văn bản) RETURNS văn bản BEGIN DECLARE $ start, $ cuối INT DEFAULT 1; LOOP SET $ start = VỊ ("<", $ str, $ bắt đầu); NẾU (! $ Bắt đầu) THEN RETURN $ str; END IF; THIẾT LẬP $ end = LOCATE (">", $ str, $ start); IF (! $ End) THEN SET $ end = $ start; END IF; Đặt $ str = INSERT ($ str, $ start, $ end - $ start + 1, ""); END LOOP; END // dấu phân cách; ' – nzn

+0

CHỨC NĂNG DROP NẾU EXISTS strip_tags; DELIMITER | TẠO CHỨC NĂNG strip_tags ($ str văn bản) RETURNS văn bản BEGIN DECLARE $ bắt đầu, $ end INT DEFAULT 1; LOOP SET $ start = LOCATE ("<", $ str, $ start); IF (! $ Bắt đầu) THEN RETURN $ str; END IF; SET $ end = LOCATE (">", $ str, $ start); IF (! $ End) THEN SET $ end = $ start; END IF; SET $ str = INSERT ($ str, $ start, $ end - $ start + 1, ""); END LOOP; END; | DELIMITER; – IRvanFauziE

5

Tôi đang chuyển mã này, có vẻ rất giống với ở trên. Làm việc cho tôi, hy vọng nó sẽ giúp.

BEGIN 
    DECLARE iStart, iEnd, iLength INT; 

    WHILE locate('<', Dirty) > 0 AND locate('>', Dirty, locate('<', Dirty)) > 0 
    DO 
    BEGIN 
     SET iStart = locate('<', Dirty), iEnd = locate('>', Dirty, locate('<', Dirty)); 
     SET iLength = (iEnd - iStart) + 1; 
     IF iLength > 0 THEN 
     BEGIN 
      SET Dirty = insert(Dirty, iStart, iLength, ''); 
     END; 
     END IF; 
    END; 
    END WHILE; 
    RETURN Dirty; 
END 
+2

Tôi đã làm một điểm chuẩn thô nhỏ trên 5000 (~ 20mb) các mẫu văn bản/html thuần túy khác nhau (mô tả công việc cóp nhặt). Đầu ra của ví dụ của bạn là chính xác giống như của Boann, tuy nhiên mã của bạn đã ~ 32s để xử lý và Boann chỉ 7s làm ** Boann của giải pháp 4,5x nhanh hơn **. Tôi chỉ đưa nó vào đây để tham khảo trong tương lai nếu ai đó sẽ đối mặt với tình trạng khó xử tương tự như tôi đã làm. Cảm ơn cả hai bạn. –

1

Tác phẩm của Boann khi tôi thêm SET $str = COALESCE($str, '');.

từ này post:

Cũng cần lưu ý, bạn có thể muốn đặt một SET $ str = liên hiệp ($ str, ''); ngay trước vòng lặp nếu không giá trị null có thể gây ra sự cố/không bao giờ truy vấn kết thúc. - Tom C ngày 17 tháng 8 tại 9:51

1

Tôi đang sử dụng thư viện lib_mysqludf_preg cho điều này và một regex như thế này:

SELECT PREG_REPLACE('#<[^>]+>#',' ',cell) FROM table; 

Cũng đã làm nó như thế này cho các hàng mà với các thực thể html mã hóa:

SELECT PREG_REPLACE('#&lt;.+?&gt;#',' ',cell) FROM table; 

Có thể những trường hợp này có thể không thành công nhưng tôi chưa gặp phải bất kỳ sự cố nào và chúng khá nhanh.

0

Tôi vừa mở rộng câu trả lời @boann để cho phép nhắm mục tiêu của bất kỳ thẻ cụ thể nào để chúng tôi có thể thay thế từng thẻ một bằng mỗi lần gọi hàm. Bạn chỉ cần chuyển thông số thẻ, ví dụ: 'a' để thay thế tất cả các thẻ mở/đóng neo. Điều này trả lời câu hỏi được hỏi bởi OP, không giống như câu trả lời được chấp nhận, trong đó loại bỏ tất cả các thẻ.

# MySQL function to programmatically replace out specified html tags from text/html fields 

# run this to drop/update the stored function 
DROP FUNCTION IF EXISTS `strip_tags`; 

DELIMITER | 

# function to nuke all opening and closing tags of type specified in argument 2 
CREATE FUNCTION `strip_tags`($str text, $tag text) RETURNS text 
BEGIN 
    DECLARE $start, $end INT DEFAULT 1; 
    SET $str = COALESCE($str, ''); 
    LOOP 
     SET $start = LOCATE(CONCAT('<', $tag), $str, $start); 
     IF (!$start) THEN RETURN $str; END IF; 
     SET $end = LOCATE('>', $str, $start); 
     IF (!$end) THEN SET $end = $start; END IF; 
     SET $str = INSERT($str, $start, $end - $start + 1, ''); 
     SET $str = REPLACE($str, CONCAT('</', $tag, '>'), ''); 
    END LOOP; 
END; 

| DELIMITER ; 

# test select to nuke all opening <a> tags 
SELECT 
    STRIP_TAGS(description, 'a') AS stripped 
FROM 
    tmpcat; 

# run update query to replace out all <a> tags 
UPDATE tmpcat 
SET 
    description = STRIP_TAGS(description, 'a');