c# - 使用 C# 处理固定宽度的源文件

标签 c# sql ssis

问题

当前数据

........Column 1....Column 2.......Column3....Column 4

Row1...........0...........0.............0...........Y    
Row2.......3142.56...........500............0...........N    
Row3.......3142.56...........500............0...........N

源文件具有固定宽度的列 导出固定宽度列的程序不包括小数点后的数字作为保留的固定宽度大小的一部分

  • 第 1 行是正常输出并且工作正常
  • 第 2 行和第 3 行有 2 位小数,因此第 2、3、4 列...都被推后 2 位。

我已经创建了一个 C# 脚本来重写文件并尝试解决这个问题。

我找到了一种读取行并将其拆分为列的方法。这成为一个字符串变量。 但是需要确定字符串是否包含“0-9”后跟“.”。图案。 然后我需要计算模式后有多少位小数。 然后删除X个空格(开头的小数位数)。

所以

当前状态 [_ _ _ _ _3142.56]

之后我们想看到什么 [_ _ _3142.56]

到目前为止的尝试 到目前为止,我已经能够发现 Regex 似乎可以满足我的需求。那么IndexOf(".").length可以用来统计小数点后的位数。

所以我想出了下面的

        // Resolve Decimal Issues
        foreach (object Column in splitLine)
        {
            String CurrentColumn = Column.ToString();

            if (Regex.Match(CurrentColumn, @"^[0-9]+(\.[0-9]+)?$").Success == true)
            {
                // Count how many numbers AFTER a decimal
                int decimalLength = CurrentColumn.Substring(CurrentColumn.IndexOf(".")).Length;
                if (decimalLength >= 1)
                {
                    // Remove this amount of places from the start of the string
                    CurrentColumn = CurrentColumn.Substring(CurrentColumn.Length - decimalLength);
                }
            }

             //Start re-joining the string
            newLine = newLine + CurrentColumn + "\t";
        }

问题是 IndexOf 在找不到匹配项时返回 -1,从而导致错误。

错误堆栈

Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. 
---> System.ArgumentOutOfRangeException: StartIndex cannot be less than zero.

Parameter name: startIndex
   at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)
   at ST_dd38f3d289db4495bf07257723356ed3.csproj.ScriptMain.Main()

   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
   at System.Type.InvokeMember(String name, BindingFlags invokeAttr, Binder binder, Object target, Object[] args, CultureInfo culture)
   at Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine.ExecuteScript()

所以我对我能做些什么来解决这个问题感到有点困惑。我认为我在正确的道路上..但是最后一个错误让我有点迷茫。

最佳答案

我认为你的逻辑有问题。

给定 bbbb123.45(b 是一个空格),您的逻辑将给出 3 的 decimalLengthCurrentColumn.Substring (CurrentColumn.Length - decimalLength) 将返回 .45

您真正想要的是 CurrentColumn.Substring(decimalLength),它将从第 3 个字符开始并返回 b123.45

方法大致相同:

    // Resolve Decimal Issues
    foreach (object Column in splitLine)
    {
        String CurrentColumn = Column.ToString();

        if (Regex.IsMatch(CurrentColumn, @"^[0-9]+(\.[0-9]+)?$"))
        {
            // If there's a decimal point, remove characters from the front
            // of the string to compensate for the decimal portion.
            int decimalPos = CurrentColumn.IndexOf(".");
            if (decimalPos != -1)
            {
                CurrentColumn = CurrentColumn.Substring(CurrentColumn.Length - decimalPos);
            }
        }

         //Start re-joining the string
        newLine = newLine + CurrentColumn + "\t";
    }

顺便说一下,如果小数部分的长度超过了字符串前面的空格数,那么这会非常失败。从你的描述来看,我认为这不是问题。但请记住这一点。

关于c# - 使用 C# 处理固定宽度的源文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17184710/

相关文章:

sql - SSIS 存储过程调用

sql - SSIS 在控制流任务之间传递数据源

sql - 在 SSIS 中将月份名称更改为月份编号

c# - 找不到 Entity Framework 方法;版本问题?

c# - 为什么 EventHandler 在以下 asp.net 代码中不触发?

javascript - AngularJS 中的数组未获取字符串值

c# - 在 ALB 上使用 Cognito 用户池进行 ASP.NET Core 身份验证

sql - 如何从Sybase数据库获取表描述(字段名称和类型)?

mysql - 如何根据mysql中的聚合列添加排名列?

sql-server - 为什么我在 Oracle DATE 列中看到值 '2432-82-75 50:08:01'?