AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 17454
Accepted
Scott Chamberlain
Scott Chamberlain
Asked: 2012-05-05 05:37:31 +0800 CST2012-05-05 05:37:31 +0800 CST 2012-05-05 05:37:31 +0800 CST

将文本列中的 RTF 批量转换为纯文本

  • 772

我有一个旧系统,表中有大约 1000 万行。在该表中有一个 type 列text,其中大部分是标准文本,但大约 50 万行中有 RTF 标记。我需要将 RTF 格式的文本转换为纯文本。

我当前的方法是我有一个 C# 程序,它使用 a 将查询加载到 DataTable 中,SqlDataAdapter并使用 winformsRichTextBox控件进行转换。

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);
    }
}

这对于小表来说非常有用,但是这是我第一次不得不在具有如此大数据集的表上运行它(一些 rtf 文件的大小可以是几兆字节,并带有嵌入的图片),而且我得到了 OutOfMemory我的 C# 程序出错。

我知道我可以将我的查询分成更小的批次,但我想看看是否有更好的方法可以去除 RTF 格式。

我应该只做与当前解决方案相同的事情,但一次只查询较小的数据块,还是有更好的方法来做到这一点?

sql-server sql-server-2005
  • 4 4 个回答
  • 26637 Views

4 个回答

  • Voted
  1. Best Answer
    Scott Chamberlain
    2012-05-05T12:21:16+08:002012-05-05T12:21:16+08:00

    我最终制作了一个 CLR 函数来转换它。

    我找到了这个库,然后对它进行了一点调整,以删除我不需要的东西,比如日志记录和绘图方法,这让我可以将它标记为安全。

    然后我就做了这个小班。

    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;
        }
    }
    

    并在 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
    

    而且速度很快,效果很好!

    • 5
  2. Ian Forrest
    2014-05-31T10:47:26+08:002014-05-31T10:47:26+08:00

    我使用 Itenso RTF DLL 和 Scott Chamberlain 做了同样的事情,但在我的情况下,在我的 SQL 2008R2 数据库中将其标记为 SAFE 之前,还有很多工作要做。

    首先,像 Scott 一样,我必须删除对 System.Drawing 的引用。我发现最简单的方法是删除引用,重新编译,然后重写正在使用该库的代码位。在大多数情况下,我只是从使用它的 VOID 函数中删除了所有代码,而在我无法将绘图/颜色对象更改为“对象”对象的情况下。

    我必须做的另一件事是删除对 log4net 的所有引用,因为它引用了一个库 System.DirectoryServices,它也不能被标记为安全。这有点困难,但通常我采用相同的方法。

    最后,在我这样做之后,我收到了关于设置静态值的投诉,这在 SAFE CLR 函数中是不允许的。所以我更新了代码以将所有静态值更改为 READONLY 并且有效(这几乎都在代码的“日志记录”部分中,我并不真正关心任何方式)。

    我最终的 CLR 代码如下所示:

    [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;
    }
    
    • 2
  3. datagod
    2012-05-05T07:43:41+08:002012-05-05T07:43:41+08:00

    我写了一个小 SQL 函数,从标记字符串中刮取文本: http ://cookingwithsql.com/index.php?option=com_content&task=view&id=65&Itemid=60

    不幸的是,它只能处理最多 8000 个字符的字符串数据。如果您在 SQL 2005 及更高版本上运行,也许可以将其更改为使用 varchar(max)。

    用法:

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

    我将在此处发布源代码以供快速参考。

    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
    
    • 1
  4. Turntwo
    2013-06-22T16:29:56+08:002013-06-22T16:29:56+08:00

    如果您使用 DataReader 而不是 DataTable,则可以一次处理一行,而不是将其全部加载到内存中。那应该绕过您的内存不足错误。

    • 1

相关问题

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve