代码之家  ›  专栏  ›  技术社区  ›  Tom Schreck

从整数和小数字符串中删除字符的最有效方法

  •  0
  • Tom Schreck  · 技术社区  · 6 年前

    我正在将原始的美国人口普查数据处理到SQL Server数据库中。解压后的tar文件会产生14000多个CSV文件,需要处理成266个不同的数据库表。我必须遍历每个CSV文件并在文件中附加一个头,这样SSIS就可以将原始数据ETL到目标sqlserver表中。

    每个CSV文件的前6列完全相同。每个文件的其余列是不同的。其余列中的数据主要是数值(整数和小数)。然而,美国人口普查局添加了一些被称为“jam”值的字符来表示为什么没有价值。我需要用null或空字符串替换这些jam值,因为目标数据库表列是小数,jam值会导致ssi插入失败。

    1. 创建StringBuilder变量
    2. 将行标题附加到StringBuilder以便SSIS正常工作
    3. 对于每一行,我必须拆分前6列,因为我需要目标表中的这些字符串。然后,我将剩余的列分开,因为我必须删除留下数字数据的jam值
    4. 将前6列和清理后的数据合并到一行中
    5. 将新清理的行附加到StringBuilder
    6. 在完成对所有行的循环之后,将StringBuilder写入目标文件夹,SSIS将加载到数据库中。

    1. 循环超过14000个文件
    2. 对于每个文件,循环每行

    下面是我在每个文件上循环的代码:

        private static Boolean BuildCensusDataFileWithHeader(String censusDataFilePath, String rowHeader, String censusDataDestinationFilePath)
        {
            try
            {
                // BUILD NEW FILE WITH HEADER
                StringBuilder currentContent = new StringBuilder();
                currentContent.Append(rowHeader + Environment.NewLine);
    
                //RETRIEVE ALL LINES IN TARGET FILE
                List<String> rawList = File.ReadAllLines(censusDataFilePath).ToList();
    
                // LOOP THROUGH EACH LINE AND REMOVE ANY STRINGS IN COLUMNS AFTER COLUMN 6
                // NOTE: COLUMNS 1-6 CONTAINS STRINGS NEEDED IN DATABASE
                foreach (var row in rawList)
                {
                    //TURN COMMA DELIMITED ROW OF DATA INTO ARRAY
                    String[] rowArray = row.Split(",");
    
                    // PEEL OFF FIRST 6 COLUMNS TO BE KEPT AS IS
                    IList<String> goodStrings = rowArray.Take(6).ToList();
    
                    // RETRIEVE REMAINING COLUMNS TO BE CLEANED OF STRINGS
                    IList<String> stringsToNullList = rowArray.Skip(6).ToList();
    
                    // REMOVE ALL STRINGS
                    stringsToNullList.OnlyDecimalValues();
    
                    // PUT GOOD COLUMNS AND CLEANED COLUMNS BACK TOGETHER AS A ROW
                    var cleanedRow = $"{String.Join(",", goodStrings)},{String.Join(",", stringsToNullList)}";
    
                    // APPEND ROW TO NEW DOCUMENT TO BE WRITTEN TO TARGET DIRECTORRY CONTAINING CLEANED DATA
                    currentContent.Append(cleanedRow + Environment.NewLine);
                }
    
                File.WriteAllText(censusDataDestinationFilePath, currentContent.ToString());
    
                return true;
            }
            catch (Exception ee)
            {
                string temp = ee.Message;
                return false;
            }
        }
    

    以下是我用空格替换字符的扩展方法:

        public static void OnlyDecimalValues(this IList<String> stringToClean)
        {
            for (int i = 0; i < stringToClean.Count; ++i)
            {
                stringToClean[i] = (stringToClean[i].IsDecimal()) ? stringToClean[i] : "";
            }
        }
    
        public static bool IsDecimal(this string text)
        {
            decimal test;
            return decimal.TryParse(text, out test);
        }
    

    这一切都是通过蛮力编程实现的。有没有更有效的方法?

    谢谢你抽出时间。

    0 回复  |  直到 6 年前
        1
  •  0
  •   Marina Melin    6 年前

    我有两个建议可以加快速度。 首先,由于您不需要对解析后的十进制值执行任何操作,所以可以使用正则表达式来检查字符串是否只包含数字。用台拉斯要快得多。我用秒表来检查速度,这样一来,对于“假”的情况会产生稍微好一点的性能,而对于“真”的情况则会产生明显的更好的性能。因此,IsDecimal方法将变为:

    private static bool IsDecimal(string text)
    {
        var regex = @"^-?(0|[1-9]\d*)(\.\d+)?$";
        return Regex.Match(text, regex).Success;
    }
    

    stringToClean[i] = (stringToClean[i].IsDecimal()) ? stringToClean[i] : "";
    

    会变成这样:

    if (!stringToClean[i].IsDecimal())
    {
        stringToClean[i] = "";
    }
    
        2
  •  0
  •   J Sidhu    6 年前

    使用ssis遍历文件夹中的所有文件,并将原始文本行加载到新创建的原始表中。 然后使用sql代码来完成其余的处理。您可以使用charindex或patIndex函数来分割原始行,SQL的一个好处将大大减少运行时,因为您将在一个给定文件的单个事务中处理整个批处理。

    另一个可能的好处是,您可能只需要为所有不同的文件创建一个raw表,包含三个列:id、fileName和rawText。所以设计看起来像:

    在SSIS中执行的步骤

    • 创建StringBuilder变量。将行头追加到StringBuilder,以便SSIS在文件中的每一行上循环。

    在SQL中执行的步骤

    • 分离出前6列 目标表中的字符串&拆分出要删除的其余列 使用单个select语句将值阻塞,并使用 patindex charindex replace 用于清除阻塞值的函数。