Chuyển đổi RTF trong một cột văn bản thành văn bản đơn giản


8

Tôi có một hệ thống kế thừa với khoảng 10 triệu hàng trong một bảng. Trong bảng đó có một cột loại text, hầu hết trong số chúng là văn bản tiêu chuẩn nhưng khoảng 500 nghìn hàng có đánh dấu RTF trong đó. Tôi cần chuyển đổi văn bản có định dạng RTF thành văn bản thuần túy.

Phương thức hiện tại của tôi là tôi có một chương trình C # tải truy vấn vào DataTable bằng cách sử dụng a SqlDataAdaptervà sử dụng RichTextBoxđiều khiển winforms để thực hiện chuyển đổi.

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    count = 0;

    rtbRTFToPlain = new RichTextBox();

    using (SqlDataAdapter ada = new SqlDataAdapter("select note_guid, notes from client_notes", Globals.SQLConnectionString))
    using(SqlCommandBuilder cmb = new SqlCommandBuilder(ada))
    {
        DataTable dt = new DataTable();
        ada.UpdateCommand = cmb.GetUpdateCommand();

        ada.Fill(dt);

        int reportEvery = dt.Rows.Count / 100;
        if (reportEvery == 0)
            reportEvery = 1;
        foreach (DataRow row in dt.Rows)
        {
            if (count % reportEvery == 0)
                bw.ReportProgress(count / reportEvery);

            try
            {
                if (((string)row["notes"]).TrimStart().StartsWith("{") == true)
                {
                    rtbRTFToPlain.Rtf = (string)row["notes"];
                    row["notes"] = rtbRTFToPlain.Text;
                }
            }
            catch
            {
            }

            count++;

        }
        bw.ReportProgress(100);

        this.Invoke(new Action(() => 
            {
                this.ControlBox = false;
                this.Text = "Updating database please wait";
            }));
        ada.Update(dt);
    }
}

Điều này rất tốt cho các bảng nhỏ, tuy nhiên đây là lần đầu tiên tôi phải chạy nó trên một bảng có tập dữ liệu lớn như vậy (một số tệp rtf có thể có kích thước vài megabyte với các hình ảnh nhúng) và tôi đang nhận được OutOfMemory lỗi với chương trình C # của tôi.

Tôi biết rằng tôi có thể chia nhỏ truy vấn của mình thành một lô nhỏ hơn, nhưng tôi muốn xem liệu có cách nào tốt hơn mà tôi đã bỏ qua để loại bỏ định dạng RTF hay không.

Tôi có nên làm điều tương tự như giải pháp hiện tại của mình nhưng chỉ truy vấn dữ liệu các phần nhỏ hơn tại một thời điểm, hoặc có cách nào tốt hơn để làm điều này không?

Câu trả lời:


5

Tôi đã kết thúc việc tạo một hàm CLR để chuyển đổi nó.

Tôi tìm thấy thư viện này , sau đó tôi đã tinh chỉnh nó một chút để loại bỏ những thứ tôi không cần như ghi nhật ký và phương pháp Vẽ, cho phép tôi đánh dấu nó là an toàn.

Sau đó tôi chỉ làm lớp học nhỏ này.

using System.Data.SqlTypes;
using Itenso.Rtf.Converter.Text;
using Itenso.Rtf.Support;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlFunction]
    public static SqlString RtfToPlainText(SqlString text)
    {
        if (text.Value.StartsWith(@"{\rtf"))
        {
            RtfTextConverter textConverter = new RtfTextConverter();
            RtfInterpreterTool.Interpret(text.Value, textConverter);
            return textConverter.PlainText;
        }
        else
            return text;
    }
}

Và chạy nó trong SQL

sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO

CREATE ASSEMBLY ConversionsSqlExtensionsAssembly 
from 'E:\Code\ConversionsSqlExtensions\bin\Debug\ConversionsSqlExtensions.dll' 
WITH PERMISSION_SET = safe
go

CREATE function RtfToPlainText(@value nvarchar(max))
returns nvarchar(max)
AS EXTERNAL NAME ConversionsSqlExtensionsAssembly.StoredProcedures.RtfToPlainText

Và nó là nhanh chóng và làm việc tuyệt vời!


1
Giải pháp của bạn trông thực sự tốt đẹp. Tôi cố gắng mà không thành công để loại bỏ các phương pháp đăng nhập và Vẽ từ thư viện RTF. Tôi có thể yêu cầu bạn cho thư viện sửa đổi? Cảm ơn Daniel Eyer

@ user22279 Xem câu trả lời của Ian cho các bước rất giống với những gì tôi đã thực hiện để làm cho thư viện có thể được đánh dấu là "AN TOÀN".
Scott Chamberlain

2

Tôi đã làm điều tương tự như Scott Chamberlain với Itenso RTF DLL, nhưng trong trường hợp của tôi, có rất nhiều việc phải làm trước khi điều này có thể được đánh dấu là SAFE trong cơ sở dữ liệu SQL 2008R2 của tôi.

Đầu tiên, giống như Scott, tôi phải xóa tham chiếu đến System.Drawing. Tôi tìm thấy cách dễ nhất để làm điều đó là xóa tham chiếu, biên dịch lại và sau đó viết lại các bit mã đang sử dụng thư viện. Trong hầu hết các trường hợp, tôi chỉ xóa TẤT CẢ mã khỏi các hàm VOID đang sử dụng nó và trong các tình huống tôi không thể thay đổi các đối tượng Vẽ / Màu thành chỉ các đối tượng "đối tượng".

Một điều khác tôi phải làm là xóa bất kỳ và tất cả các tham chiếu đến log4net vì nó tham chiếu thư viện System.DirectoryService không thể được đánh dấu là an toàn. Điều này khó hơn một chút nhưng nhìn chung tôi đã thực hiện cùng một cách tiếp cận.

Cuối cùng, sau khi tôi làm điều đó, tôi đã nhận được khiếu nại về việc đặt các giá trị tĩnh, không được phép trong hàm SAFE CLR. Vì vậy, tôi đã cập nhật mã để thay đổi tất cả các giá trị Tĩnh thành S READN SÀNG và nó đã hoạt động (điều này khá nhiều trong phần "ghi nhật ký" của mã mà tôi không thực sự quan tâm về bất kỳ cách nào).

Mã CLR cuối cùng của tôi trông giống như vậy:

[Microsoft.SqlServer.Server.SqlFunction]
[return: SqlFacet(MaxSize=-1)]
public static SqlChars RTFFix([SqlFacet(MaxSize=-1)]string rtfField)
{
    SqlChars returnChars;
    try
    {

        RtfTextConverter textConverter = new RtfTextConverter();
        RtfInterpreterTool.Interpret(rtfField, textConverter);
        returnChars = new SqlChars(new SqlString(textConverter.PlainText.Trim()));
    }
    catch (Exception e)
    {
        returnChars = new SqlChars(new SqlString(rtfField));
    }
    return returnChars;
}

Cảm ơn bạn đã đăng câu trả lời chi tiết cách chuyển đổi thư viện sang thư viện an toàn. Tôi không muốn chia sẻ những gì tôi đã làm trong câu trả lời của mình vì thư viện tôi đã sửa đổi đã được cấp phép GPL (dường như bây giờ là COPL được cấp phép) và tôi lo ngại chia sẻ bất kỳ thay đổi nào có thể là "phân phối", điều này đòi hỏi tôi phải làm nhiều hơn nữa theo GPL.
Scott Chamberlain

1

Tôi đã viết một hàm SQL nhỏ loại bỏ văn bản ra khỏi chuỗi markup-ish: http://cookingwithsql.com/index.php?option=com_content&task=view&id=65&Itemid=60

Thật không may, nó sẽ chỉ xử lý dữ liệu chuỗi tối đa 8000 ký tự. Có lẽ nó có thể được thay đổi để sử dụng varchar (max), nếu bạn đang chạy trên SQL 2005 trở lên.

sử dụng:

select dbo.ScrapeText('<I love SQL> gobbldygook font 12 blah blah') as 'Result'

Result
----------------------------
I love SQL

Tôi sẽ đăng nguồn ở đây để tham khảo nhanh.

use master
IF (object_id('dbo.ScrapeText') IS NOT NULL)
BEGIN
  PRINT 'Dropping: dbo.ScrapeText'
  DROP function dbo.ScrapeText
END
GO
PRINT 'Creating: dbo.ScrapeText'
GO
CREATE FUNCTION dbo.ScrapeText 
(
  @string varchar(8000)
) 
returns varchar(8000)

AS
BEGIN
---------------------------------------------------------------------------------------------------
-- Title:        ScrapeText
--               
-- Date Created: April 4, 2006
--               
-- Author:       William McEvoy
--               
-- Description:  This function will attempt to remove markup language formatting from a string. This is 
--               accomplished by concetenating all text contained between greater than and less 
--               than signs within the formatted text.  
--               
---------------------------------------------------------------------------------------------------
-- Date Revised: 
-- Author:       
-- Reason:       
---------------------------------------------------------------------------------------------------

declare @text  varchar(8000),
        @PenDown char(1),
        @char  char(1),
        @len   int,
        @count int

select  @count = 0,
        @len   = 0,
        @text  = ''


---------------------------------------------------------------------------------------------------
-- M A I N   P R O C E S S I N G
---------------------------------------------------------------------------------------------------

-- Add tokens
select @string = '>' + @string + '<'

-- Replace Special Characters
select @string = replace(@string,' ',' ')

-- Parse out the formatting codes
select @len = len(@string)
while (@count <= @len)
begin
  select @char = substring(@string,@count,1)

  if (@char = '>')
     select @PenDown = 'Y'
  else 
  if (@char = '<')
    select @PenDown = 'N'
  else  
  if (@PenDown = 'Y')
    select @text = @text + @char

  select @count = @count + 1
end

RETURN @text
END
GO
IF (object_id('dbo.ScrapeText') IS NOT NULL)
  PRINT 'Function created.'
ELSE
  PRINT 'Function NOT created.'
GO

Mặc dù điều này có thể làm việc cho văn bản html, nhưng giải pháp này là vô ích đối với RTF.
Scott Chamberlain

1

Nếu bạn sử dụng DataReader thay vì DataTable, bạn có thể xử lý từng hàng một thay vì tải tất cả vào bộ nhớ. Điều đó sẽ bỏ qua lỗi bộ nhớ của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.