C#-将大字符串分成多个小字符串以导出到数据库

时间:2019-04-23 16:12:17

标签: c#

这里的C#newb-我有一个用C#编写的脚本,该脚本接收应用程序(在本例中为Contoso Application)内部数据库的多个字段的内容,并将其导出到SQL Server数据库表中。

代码如下:

using System;
using System.IO;
using System.Data.SqlClient;
using Contoso.Application.Api;
using Contoso.Application.Commands;
using System.Linq;

public class Script
{
    public static bool ExportData(DataExportArguments args)
    {
        try
        {
            var sqlStringTest = new SqlConnectionStringBuilder();

            sqlStringTest.DataSource = "SQLserverName";
            sqlStringTest.InitialCatalog = "TableName";
            sqlStringTest.IntegratedSecurity = True;
            sqlStringTest.UserID = "userid";
            sqlStringTest.Password = "password";


            using (var sqlConnection = new SqlConnection(sqlStringTest.ConnectionString))
            {
                sqlConnection.Open();
                using (IExportReader dataReader = args.Data.GetTable())
                {
                    while (dataReader.Read())
                    {   
                        using (var sqlCommand = new SqlCommand())
                        {
                            sqlCommand.Connection = sqlConnection;

                            sqlCommand.CommandText = 
                            @"INSERT INTO [dbo].[Table] (
                            Id, 
                            Url,
                            articleText)
                             VALUES (
                            @Id, 
                            @Url,
                            @articleText)";

                            sqlCommand.Parameters.AddWithValue("@Id", dataReader.GetStringValue("Id"));
                            sqlCommand.Parameters.AddWithValue("@Url", dataReader.GetStringValue("Url"));
                            sqlCommand.Parameters.AddWithValue("@articleText", 
                                    dataReader.Columns.Any(x => x.Name == "articleText") 
                                    ? dataReader.GetStringValue("articleText") 
                                    : (object)DBNull.Value);
                        }
                    }
                }
            }
        }
        catch (Exception exp)
        {
            args.WriteDebug(exp.ToString(), DebugMessageType.Error);
            return false;
        }
        return true;
    }
}

仅供参考-articleText的类型为nvarchar(max)

我要完成的工作:有时articleText字段中的数据很短,有时很长。我需要做的是,当给定articleText字段中的字符串大于10,000个字符时,将一条记录分成多个记录。因此,如果给定的articleText字段为25,000个字符,则将导出3条记录:第一个记录的articleText字段为10,000个字符,第2个,10,000个字符,第3个,5,000个字符。

除此要求外,我还需要确保,如果每条记录的字符截断值落在一个单词的中间(大多数情况下可能会发生),那么我会对此加以说明。

因此,举例来说,如果我们在应用程序的内部数据库中有一个记录,其中Id为1,www.contoso.com的Url为28,000个字符,我想这样将3条记录导出到SQL Server:

articleText

对于任何给定的导出会话,内部数据库中都有成千上万条记录要导出(因此while循环)。大约20%的记录将满足Record 1: Id: 1 Url: www.contoso.com articleText: if articleText greater than 10,000 characters, export characters 1-10,000, else export entirety of articleText. Record 2: Id: 1 Url: www.contoso.com articleText: assuming Record 2 only exists if Record 1 was greater than 10k character, export characters 9,990-20,000 (start at character 9,990 in case Record 1 cuts off at the middle of a word). Record 3: Id: 1 Url: www.contoso.com articleText: export characters 19,900-28,000 (or alternatively, 19,900 through end of string). 超过1万个字符的条件,因此对于任何不符合的条件,我们绝对只希望导出一个记录。此外,尽管我上面的示例仅包含28k个字符,但此脚本需要能够容纳任何大小。

我对实现这样的目标感到有些困惑。我相信第一步是获取articleText的字符数,以确定需要导出多少记录。从那里,我觉得我掉进了一个兔子洞。对此的任何建议将不胜感激。

编辑#1:要澄清截止要求-上面是我建议处理截止方法的原因是因为文章中可能有一个人的名字。仅仅找到一个空间并将其切掉是行不通的,因为您可能会将名字和姓氏分开。我上面提到的方法可以满足我们的要求,因为单词或名称只需要在记录的一个中完整存在。

此外,在SQL Server中重组分离的记录不是必需的,因此不是必需的。

2 个答案:

答案 0 :(得分:1)

这可能是一个开始:诚然,它不是非常有效,只是为了说明它是如何完成的:

void Main()
{
    string text = "012345 6789012 3456789012 34567890 1234567" + 
        "0123 456789 01234567 8901234567 8901234567" + 
        "012345 67890123456 78901234567890123456" + 
        "0123456 7890123456 789012345 6789012345" + 
        "012345 678901234 5678901234 5678901234" + 
        "01234567 89012345678 901234567890123" + 
        "ABCDEFGHI JLMNOPQES TUVWXYZ";

    int startingPoint = 0;
    int chunkSize = 50;
    int padding = 10;
    List<string> chunks = new List<string>();
    do
    {
        if (startingPoint == 0)
        {
            chunks.Add(new string(text.Take(chunkSize).ToArray()));
        }
        else 
        {
            chunks.Add(new string(text.Skip(startingPoint).Take(chunkSize).ToArray()));
        }

        startingPoint = startingPoint + chunkSize - padding;
    }
    while (startingPoint < text.Length);

    Console.WriteLine("Original length: {0}", text.Length);
    Console.WriteLine("Chunk count: {0}", chunks.Count);
    Console.WriteLine("Expected new length: {0}", text.Length + (chunks.Count -1) * padding);
    Console.WriteLine("Actual new length: {0}", chunks.Sum(c => c.Length));

    Console.WriteLine();
    Console.WriteLine("Chunks:");

    foreach (var chunk in chunks)
    {
        Console.WriteLine(chunk);
    }
}

输出:

  

原始长度:263
  块数:7
  预计新长度:323
  实际新长度:323

大块:

012345 6789012 3456789012 34567890 12345670123 456
670123 456789 01234567 8901234567 8901234567012345
4567012345 67890123456 789012345678901234560123456
4560123456 7890123456 789012345 6789012345012345 6
45012345 678901234 5678901234 567890123401234567 8
01234567 89012345678 901234567890123ABCDEFGHI JLMN
EFGHI JLMNOPQES TUVWXYZ

答案 1 :(得分:0)

您将必须对输入进行标记化,以便能够合理地分割输入。为此,您必须能够对输入进行一些假设。

例如,您可以在10K字符边界之前的最后一个句子结尾上拆分输入。但是,您必须能够对构成句子结尾的内容做出具体的假设。如果您可以假设输入的标点符号正确且语法正确,则可以使用简单的正则表达式(例如[^.!?]+[.!?] {1,2}[A-Z])来检测句子的结尾,该句子的结尾为“。”,“!”或“?”后跟至少一个但不超过两个空格,下一个字符为大写字母。自从 比赛中包含大写字母后,您只需放回一个字符位置并拆分即可。

确切的过程将取决于您可以对输入做出的特定假设。