【问题标题】:Validate a csv file验证 csv 文件
【发布时间】:2014-02-26 14:47:52
【问题描述】:

这是我的示例文件

#%cty_id1,#%ccy_id2,#%cty_src,#%cty_cd3,#%cty_nm4,#%cty_reg5,#%cty_natnl6,#%cty_bus7,#%cty_data8
690,ALL2,,AL,ALBALODMNIA,,,,
90,ALL2,,,AQ,AKNTARLDKCTICA,,,
161,IDR2,,AZ,AZLKFMERBALFKIJAN,,,,
252,LTL2,,BJ,BENLFMIN,,,,
206,CVE2,,BL,SAILFKNT BAFSDRTHLEMY,,,,
360,,,BW2,BOPSLFTSWLSOANA,,,,

问题在于#%cty_cd3 是一个仅长度为 2 个字母的standard column(NOT NULL),但在 sql server 中,记录转移到另一列,(由于 btw 中有一个额外的逗号)我如何验证 csv 文件,以确保 当有 2 个字符的词只需要在 4 列中?

大约有 10000 条记录?

定义的规则集!

Should have a standard set of delimiters for eachrow
 if not
   Check for NOT NULL values having Null values
     If found Null
       remove delimiter at the pointer

3个,,,不会被2个,,替换

#UPDATED:我能知道这是否可以使用脚本来完成吗?

更新了我只需要一个对像这样的记录进行操作的函数

90,ALL2,,,AQ,AKNTARLDKCTICA,,, 使用正则表达式或任何其他方法更正它们并放回源文件!

【问题讨论】:

  • 这个 SO post 可能是你的起点
  • csv文件中多余的逗号是什么原因?为什么不能简单地将其从文件中删除?
  • @HåkonHægland..src 文件如上所示,手动删除没有帮助!因为大约有 10-15k 条记录;
  • 好的,我明白了.. 但是使用 awk 删除它们应该很容易..
  • 所以您想删除两个字符列之前的额外字段(这被视为第 4 列的标志)?那么如果两个字符列之前有 5 个字段,您要删除其中一个为空的字段吗?

标签: vba vbscript


【解决方案1】:

如果这是唯一的问题(并且如果您在字段 bt_cty_ccy_id 中从来没有逗号),那么您可以通过将文件加载到支持正则表达式的编辑器并替换它来删除这样一个额外的逗号

^([^,]*,[^,]*,[^,]*,),(?="[A-Z]{2}")

\1.

【讨论】:

  • 我试过了!我在 Talend Note: Preview errors are generally due to a wrong encoding setting. org.talend.designer.runprocess.shadow.ShadowFilePreview.preview(ShadowFilePreview.java:90) org.talend.repository.ui.utils.ShadowProcessHelper.getCsvArray(ShadowProcessHelper.java:383) org.talend.repository.ui.wizards.metadata.connection.files.regexp.RegexpFileStep2Form$PreviewProcessor.nonUIProcessInThread(RegexpFileStep2Form.java:518) org.talend.commons.ui.swt.thread.SWTUIThreadProcessor$1.run(SWTUIThreadProcessor.java:74) 中遇到错误我从 Talend 阅读了文档但没有帮助!
  • 嗯,您使用了哪种编码设置,您的文件使用了哪种编码?
  • 它的UTF-8先生,我仔细检查了!
  • 与您的问题无关,但与执行有关:它与 Talend UI 有关。这些通常与一些辅助商品(即向导、元数据、存储库...)相关,而不是 talend 生成的作业代码。所以,不要在这个错误上浪费时间,这不是导致 CSV 偏斜的原因。关于问题,让我先检查你的数据:)
  • 你能帮忙吗!告诉如果没有双引号会怎样?在文件中?我是上面的正则表达式.csv file
【解决方案2】:

我会质疑向您发送此文件的源系统,为什么在某些行之间有这个额外的逗号?我猜你会使用逗号作为分隔符来将此 .csv 文件导入 talend。

(或者另一个建议是在输入文件中要求分号作为列分隔符)

9,"ALL",,,"AQ","ANTARCTICA",,,,

将会

9;"所有";,;"AQ";"南极洲";;;;

【讨论】:

  • 恕我直言 - 理想情况下它应该是你提到的!但事实并非如此!
【解决方案3】:

如果第 4 列没有,您可以尝试删除第 4 列中的空字段。 4 不是两个字符的字段,如下:

awk 'BEGIN {FS=OFS=","}
{
    for (i=1; i<=NF; i++) {
        if (!(i==4 && length($4)!=4))
            printf "%s%s",$i,(i<NF)?OFS:ORS
    }
}' file.csv

输出:

"id","cty_ccy_id","cty_src","cty_nm","cty_region","cty_natnl","cty_bus_load","cty_data_load"
6,"ALL",,"AL","ALBANIA",,,,
9,"ALL",,"AQ","ANTARCTICA",,,
16,"IDR",,"AZ","AZERBAIJAN",,,,
25,"LTL",,"BJ","BENIN",,,,
26,"CVE",,"BL","SAINT BARTH�LEMY",,,,
36,,,"BW","BOTSWANA",,,,
41,"BNS",,"CF","CENTRAL AFRICAN REPUBLIC",,,,
47,"CVE",,"CL","CHILE",,,,
50,"IDR",,"CO","COLOMBIA",,,,
61,"BNS",,"DK","DENMARK",,,,

注意:

  • 我们使用length($4)!=4,因为我们假设第 4 列中有两个字符,但我们还必须为双引号添加两个额外字符..

【讨论】:

  • 你把标题“cty_cd”剪掉了,会导致整个sql输入错误。
  • @BMW 感谢您的评论!它应该通过在顶部添加NR==1{print; next} 来修复..
【解决方案4】:

解决方案是使用前瞻正则表达式,如前所述。为了重现您的问题,我使用了这个:

"\\,\\,\\,(?=\\\"[A-Z]{2}\\\")"

匹配三个逗号后跟两个带引号的大写字母,但在匹配中不包括这些。 Ofc 您可能需要根据自己的需要对其进行一些调整(即任意数量的逗号,而不是恰好三个)。

但是您不能直接在 Talend 中使用它而不会出现大量错误。以下是设计工作的方法:

换句话说,你需要逐行读取文件,还没有字段。然后,在 tMap 中,进行匹配和替换,例如:

row1.line.replaceAll("\\,\\,\\,(?=\\\"[A-Z]{2}\\\")", ",,")

最后使用“,”作为分隔符对行进行标记以获得最终模式。您可能需要在这里和那里手动修剪引号,因为 tExtractDelimitedFields 不会。

这是一个输出示例(需要一些清理,ofc):

您无需手动输入 tExtractDelimitedFields 的架构。使用向导将 DelimitedFile Schema 记录到元数据存储库中,您可能已经这样做了。您也可以将此模式用作通用模式,使其适合 tExtractDelimitedField 的传出连接。不是纯粹主义者闲逛的东西,但它有效且节省时间。

关于您的 UI 问题,它们通常与文件编码和区域设置有关。不要太担心,它们(通常)不会影响作业的执行。

编辑:这是一个显示解决方案的示例 TOS 作业,只需在您的项目中导入:TOS job archive

EDIT2:添加了一些截图

【讨论】:

  • 我给了一个 +1..我们明天会在我进入我的系统后检查。;)
  • 我试过了,但输出文件没有变化,并且 ReplaceAll 在 tMap 组件中不起作用?
  • 在我输入row2.line.replaceAll("\\,\\,\\,(?=\\\"[A-Z]{2}\\\")", ",,") 并按test 后它显示为空?然后来自 textractdelimited 组件 Antartica 事物 doesn't get shifted 的输出?你能试着执行这个吗!并给我详细的答复?我被搞砸了!
  • 我执行了! :) 你可能会弄乱连接名称。我导出了我的示例作业并与一些屏幕截图一起上传到这里。希望这会有所帮助!
  • 以前我搞砸了..但这里有一个变化..文件(.csv)中不再有“”(双引号)
【解决方案5】:

您最好的选择可能是在 Talend 中使用 tSchemaComplianceCheck 组件。

如果您使用tFileInputDelimited 组件读取文件,然后使用tSchemaComplianceCheck 检查它,您将cty_cd 设置为不可为空,那么它将拒绝您的南极行,因为您希望没有空值。

从这里您可以使用 tMap 并将字段映射到上面的字段。

您应该能够根据需要轻松地对此进行调整,可能还可以通过进一步的tSchemaComplianceChecks 沿着拒绝行和映射来适应。这种方法更加自我解释,当您想要适应文件结构的不同变体时,您不必处理需要复杂管理的复杂正则表达式,其好处是您将始终捕获所有格式良好的行。

【讨论】:

  • 我给了一个 +1..我们明天会在我进入我的系统后检查。;)
  • 它工作正常(调整行太棒了!!)...但是我如何加入这些目的地,比如Accept goes into Excel1Right yielding goes into excel2 然后我做一个联合(tunite 没有工作?)并将其发送到数据库!
  • 令人沮丧的是,您无法在 Talend 中重新组合流程,没有明显的充分理由(可能是潜在的原因)。您可以做的是将它们输出到平面文件或数据库,然后重新读取平面文件或数据库并加入。使用 on subjob ok 链接链接子作业(甚至使用 tRunJob 单独的作业),它应该可以正常工作。如果你真的想要,你可以有另一个子作业来删除临时拆分数据。
  • 好的...但是如果是正则表达式会怎么样?我不认为调整在每种情况下都有效? (我目前处理 10k 条记录,但如果将这个解决方案提供给客户,它可能会被淘汰!!)(有效的解决方案只使用正则表达式)但非常感谢@ydea
  • 我倾向于遍历所有可能的数据组合(首先对其进行分析以查看存在的内容)并将它们全部分支到来自tSchemaComplianceCheck 组件的嵌套拒绝。一个正则表达式可能不会涵盖所有可能的实例,如果它涵盖了,那么它很可能会非常复杂,当您以后找到一个新案例时,您将无法返回并更改它以包含一个新案例。通过这种方式,您的客户可以清楚地看到正在发生的事情,甚至可以自己添加新案例。此外,您永远不必担心丢失格式良好的行。
【解决方案6】:

使用基于 VBA 的方法迟到。正则表达式的另一种方法是解析文件并在第 4 个字段为空时删除逗号。使用微软脚本运行时,可以实现代码打开文件然后读取每一行,将其复制到新的临时文件中。如果第 4 个元素是空的,如果是,它会写一行,去掉多余的逗号。然后将清理后的数据复制到原始文件并删除临时文件。这似乎有点漫长,但是当我根据您的样本在 14000 行的文件上对其进行测试时,完成时间不到 2 秒。

Sub Remove4thFieldIfEmpty()

    Const iNUMBER_OF_FIELDS As Integer = 9

    Dim str As String
    Dim fileHandleInput As Scripting.TextStream
    Dim fileHandleCleaned As Scripting.TextStream
    Dim fsoObject As Scripting.FileSystemObject
    Dim sPath As String
    Dim sFilenameCleaned As String
    Dim sFilenameInput As String
    Dim vFields As Variant
    Dim iCounter As Integer
    Dim sNewString As String

    sFilenameInput = "Regex.CSV"
    sFilenameCleaned = "Cleaned.CSV"
    Set fsoObject = New FileSystemObject

    sPath = ThisWorkbook.Path & "\"


    Set fileHandleInput = fsoObject.OpenTextFile(sPath & sFilenameInput)

    If fsoObject.FileExists(sPath & sFilenameCleaned) Then
        Set fileHandleCleaned = fsoObject.OpenTextFile(sPath & sFilenameCleaned, ForWriting)
    Else
        Set fileHandleCleaned = fsoObject.CreateTextFile((sPath & sFilenameCleaned), True)
    End If


    Do While Not fileHandleInput.AtEndOfStream
        str = fileHandleInput.ReadLine
            vFields = Split(str, ",")
            If vFields(3) = "" Then
                sNewString = vFields(0)
                For iCounter = 1 To UBound(vFields) 
                    If iCounter <> 3 Then sNewString = sNewString & "," & vFields(iCounter)
                Next iCounter
                str = sNewString
            End If
        fileHandleCleaned.WriteLine (str)
    Loop


    fileHandleInput.Close
    fileHandleCleaned.Close

    Set fileHandleInput = fsoObject.OpenTextFile(sPath & sFilenameInput, ForWriting)
    Set fileHandleCleaned = fsoObject.OpenTextFile(sPath & sFilenameCleaned)

    Do While Not fileHandleCleaned.AtEndOfStream
        fileHandleInput.WriteLine (fileHandleCleaned.ReadLine)
    Loop

    fileHandleInput.Close
    fileHandleCleaned.Close



    Set fileHandleCleaned = Nothing
    Set fileHandleInput = Nothing

    KillFile (sPath & sFilenameCleaned)

    Set fsoObject = Nothing


End Sub

【讨论】:

  • @VijaykumarHadalgi 哎呀我在代码中留下了一个错误,读取iCounter = 1 To UBound(vFields)-2 的行应该读取读取iCounter = 1 To UBound(vFields) 我已经编辑了它现在应该像expexted 一样工作的解决方案。另外,如果您愿意,当我删除逗号时,我可以在末尾添加一个额外的逗号?
  • 嗨@VijaykumarHadalgi 原始文件将具有上述更改。我们可以避免使用临时文件并在写入文件之前将行存储在内存中,或者我们可以在 excel 中打开 CSV 文件进行更改然后保存文件。我可以修改子例程以将文件名作为参数,以便可以处理任何文件。您的代码有什么问题?
猜你喜欢
  • 2019-04-23
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 2016-12-15
  • 1970-01-01
  • 2020-03-13
  • 1970-01-01
  • 2017-02-03
相关资源
最近更新 更多