使用pentaho解析文本文件

使用pentaho解析文本文件,pentaho,kettle,Pentaho,Kettle,我有大量的文本文件需要加载到数据库中。它们的结构不是更常见的csv格式,而是如下所示: TY - JOUR T1 - On the Structure and Life-History of Entyloma ranunculi (Bonorden) JF - Philosophical Transactions of the Royal Society of London. B (1887-1895) VL - 178 SP - 173 EP - 185 PY - 1887/01

我有大量的文本文件需要加载到数据库中。它们的结构不是更常见的csv格式,而是如下所示:

TY  - JOUR
T1  - On the Structure and Life-History of Entyloma ranunculi (Bonorden)
JF  - Philosophical Transactions of the Royal Society of London. B (1887-1895)
VL  - 178
SP  - 173
EP  - 185
PY  - 1887/01/01/
UR  - http://dx.doi.org/10.1098/rstb.1887.0008
M3  - doi:10.1098/rstb.1887.0008
AU  - Ward, H.
ER  -
如果每行是不同的字段,则字段名由前导字符表示


我想做的是将每一行加载到记录中相应的字段中。我想通过pentaho做到这一点,任何人都知道如何做到这一点。文本输入步骤是为csv输入设置的。

您需要使用行反规范化步骤来反规范化行

步骤:

  • 使用文本文件输入将数据读入一个字段

  • 使用字段拆分器拆分“-”上的字段

  • 对组字段中的数据进行排序(我没有在示例中标识组id)。如果没有可用的组ID,那么希望每个组有固定数量的行,然后可以添加计算出的组ID

  • 将行传递给行法线化器并指定以下内容:

    4.1。将组ID字段添加到组ID规范中的组ID中

    4.2。为字段中需要的每行添加目标字段名。我在样本中添加了11个
    来自TY、T1、JF等。它们可以是您选择的任何名称

    4.3。对于每个新字段,指定值字段名称,即分配给拆分后的第二个字段的字段。在字段拆分器中的示例中,我分配了两个字段-fld_hdr和fld_content。“我的值”字段包含fld_内容fld

    4.4。指定字段类型以及每行上的剩余列(可选)


  • 我创建了一个示例,但看不到将ktr文件上载到何处。

    您需要使用行反规范化步骤来反规范化行

    步骤:

  • 使用文本文件输入将数据读入一个字段

  • 使用字段拆分器拆分“-”上的字段

  • 对组字段中的数据进行排序(我没有在示例中标识组id)。如果没有可用的组ID,那么希望每个组有固定数量的行,然后可以添加计算出的组ID

  • 将行传递给行法线化器并指定以下内容:

    4.1。将组ID字段添加到组ID规范中的组ID中

    4.2。为字段中需要的每行添加目标字段名。我在样本中添加了11个
    来自TY、T1、JF等。它们可以是您选择的任何名称

    4.3。对于每个新字段,指定值字段名称,即分配给拆分后的第二个字段的字段。在字段拆分器中的示例中,我分配了两个字段-fld_hdr和fld_content。“我的值”字段包含fld_内容fld

    4.4。指定字段类型以及每行上的剩余列(可选)


  • 我创建了一个示例,但不知道在哪里上传ktr文件。

    该文本示例看起来非常熟悉

    匆匆忙忙地去检查一些东西

    如果这个文本示例是我认为的“皇家科学学会期刊描述文件”,那么您将无法编写pentaho脚本来解析这些内容

    我去过那里,尝试过,非常痛苦

    为什么?

    嗯,有很多事情

    首先,文件格式未经过严格检查,因此会发现一些文件中没有2个字符标识,后跟2个空格、破折号1空格和数据格式行

    您还会发现一些文件中有未解析的LATEX命令和/或未处理的变量替换

    简言之,这些文件(至少是我上次用它们做任何事情时看到的那些文件)处于一种可怕的状态

    您将遇到的另一个主要问题是缺少行

    每个描述符应该有11个主标记,如下所示:

    TY
    T1
    JF
    VL
    SP
    EP
    PY
    UR
    M3
    AU
    ER
    
    从内存中可以看出:

    TY - Title
    T1 - Description
    JF - ???
    VL - Volume number
    SP - Start page
    EP - End page
    PY - Published Year
    UR - Url
    M3 - ???
    AU - Author name
    ER - ???
    
    通常,您会发现并非所有这些行都存在,但要使列在CSV中对齐,您仍然需要添加空白条目

    还要注意AU字段,它可以而且经常包含一个文件的多个条目,因此您通常会得到:

    TY  - ....
    T1  - ....
    ....
    AU  - ....
    AU  - ....
    ....
    
    在上面Carey的回答中,使用pentaho方法处理这个问题会使您的许多行失去同步,因为这将要求每个文件的每个标记有一行

    关于Carey的答案,我不得不说这是一个非常好的答案,并且比我放弃之前所做的更接近于做一个很好的转换,但冷酷的事实是,这些文件只是不适合pentaho可靠地处理

    为此,Iv'e拿出了一些我写的C#文件,将这些文本文件放在一个文件夹中,并将它们转换成一个扁平的CSV

    生成的CSV并不完美,仍然需要进行少量调整,但它将使您达到99.9%的效果,并且使用pentaho处理生成的文件将比源文件本身更容易

    代码是相当通用的C#,因此它应该在windows和mono上编译(尽管我不得不承认,Iv'e没有在以后的版本上测试它)

    代码如下:

    using System.Collections.Generic;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace SciDataParse
    {
      class RecordData
      {
        public string TY { get; set; }
        public string T1 { get; set; }
        public string JF { get; set; }
        public string VL { get; set; }
        public string SP { get; set; }
        public string EP { get; set; }
        public string PY { get; set; }
        public string UR { get; set; }
        public string M3 { get; set; }
        public List<string> AU { get; set; }
        public string ER { get; set; }
    
        public RecordData()
        {
          AU = new List<string>();
          TY = string.Empty;
          T1 = string.Empty;
          JF = string.Empty;
          VL = string.Empty;
          SP = string.Empty;
          EP = string.Empty;
          PY = string.Empty;
          UR = string.Empty;
          M3 = string.Empty;
          ER = string.Empty;
        }
      }
    
      class Program
      {
        static RecordData ProcessFile(string inputName)
        {
          RecordData result = new RecordData();
    
          using (StreamReader reader = new StreamReader(inputName))
          {
            string inputLine = reader.ReadLine();
            while(!string.IsNullOrEmpty(inputLine))
            {
              if (!Regex.IsMatch(inputLine, @"^[A-Z,0-9][A-Z,0-9]\s+-\s+.*$"))
              {
                inputLine = reader.ReadLine();
                continue; // Regex match to ensure lines are valid format
              }
              string[] lineItems = inputLine.Split('-');
              string tag = lineItems[0].Trim();
              string data = lineItems[1].Trim();
              switch (tag)
              {
                // Sort and add lines to our result object.  Note we check and change null to empty strings and filter commas
                // so that we don't create any problems with outputting CSV data
                case "TY" :
                  result.TY = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "T1":
                  result.T1 = !string.IsNullOrEmpty(data) ? data.Replace(",", string.Empty) : string.Empty;
                  break;
    
                case "JF":
                  result.JF = !string.IsNullOrEmpty(data) ? data.Replace(",", string.Empty) : string.Empty;
                  break;
    
                case "VL":
                  result.VL = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "SP":
                  result.SP = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "EP":
                  result.EP = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "PY":
                  result.PY = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "UR":
                  result.UR = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "M3":
                  result.M3 = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
    
                case "AU":
                  // AU = Author items of which there can be multiple, note we also replace blank author names with "Unknown"
                  result.AU.Add(!string.IsNullOrEmpty(data) ? data.Replace(",", string.Empty) : "Unknown");
                  break;
    
                case "ER":
                  result.ER = !string.IsNullOrEmpty(data) ? data : string.Empty;
                  break;
              }
              inputLine = reader.ReadLine();
            }
          }
    
          return result;
        }
    
        static void Main()
        {
          List<RecordData> fileRecords = new List<RecordData>();
          List<string> headerColumns = new List<string> {"TY", "T1", "JF", "VL", "SP", "EP", "PY", "UR", "M3", "AU", "ER"};
    
          string baseFolder = Directory.GetCurrentDirectory();
    
          string[] fileNames = Directory.GetFiles(baseFolder, "*.txt");
    
          foreach (string fileName in fileNames)
          {
            fileRecords.Add(ProcessFile(fileName));
          }
    
          using (StreamWriter writer = new StreamWriter("consolodated_data.csv"))
          {
            string headerRow = string.Join(",", headerColumns);
            writer.WriteLine(headerRow);
    
            foreach (RecordData fileRecord in fileRecords)
            {
              string fileLine = string.Empty;
              fileLine += fileRecord.TY + ",";
              fileLine += fileRecord.T1 + ",";
              fileLine += fileRecord.JF + ",";
              fileLine += fileRecord.VL + ",";
              fileLine += fileRecord.SP + ",";
              fileLine += fileRecord.EP + ",";
              fileLine += fileRecord.PY + ",";
              fileLine += fileRecord.UR + ",";
              fileLine += fileRecord.M3 + ",";
              fileLine += string.Join("|",fileRecord.AU) + ","; // Join author names with a |
              fileLine += fileRecord.ER;
              writer.WriteLine(fileLine);
            }
          }
    
        }
      }
    }
    
    使用System.Collections.Generic;
    使用System.IO;
    使用System.Text.RegularExpressions;
    命名空间数据解析
    {
    类记录数据
    {
    公共字符串TY{get;set;}
    公共字符串T1{get;set;}
    公共字符串JF{get;set;}
    公共字符串VL{get;set;}
    公共字符串SP{get;set;}
    公共字符串EP{get;set;}
    公共字符串PY{get;set;}
    公共字符串UR{get;set;}
    公共字符串M3{get;set;}
    公共列表AU{get;set;}
    公共字符串ER{get;set;}
    公共记录数据()
    {
    AU=新列表();
    TY=string.Empty;
    T1=字符串。空;
    JF=string.Empty;
    VL=字符串。空;
    SP=string.Empty;
    EP=字符串。空;
    PY=string.Empty;
    UR=字符串。空;
    M3=字符串。空;
    ER=字符串。空;
    }
    }
    班级计划
    {