1

データベースにロードする必要がある多数のテキスト ファイルがあります。通常の 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  -

各行は異なるフィールドであり、フィールド名は先頭の文字で示されます。

私がやりたいことは、各行をレコードの対応するフィールドにロードすることです。私はペンタホ経由でこれをやりたいと思っています。誰もがこれを達成する方法を知っています。テキスト入力ステップは csv 入力用に設定されています。

4

2 に答える 2

5

そのテキストサンプルはひどく見覚えがあります.....

急いで何かを確認する

そのテキスト サンプルが「王立科学協会ジャーナル記述ファイル」であると私が考えるものである場合、これらを解析するペンタホ スクリプトを作成することはできません。

私はそこに行って試してみましたが、とても苦痛でした。

なんで?

まあいろいろ。

まず、ファイル形式は厳密にチェックされていないため、2 文字の ID の後に 2 つのスペース、ダッシュ 1 つのスペース、およびデータ形式の行が続くファイルがいくつか見つかります

また、解析されていない LATEX コマンド未処理の変数置換が含まれているファイルもあります。

要するに、ファイル (少なくとも、私が最後に何かを行ったときに見たもの) は恐ろしい状態にありました。

もう 1 つの主な問題は、行の欠落です。

すべての記述子には、次のように 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 メソッドを使用してこれを処理すると、ファイルごとにタグごとに 1 つの行が予想されるため、多くの行が同期されなくなります。

キャリーの答えについては、それは非常に良い答えだと言わざるを得ず、あきらめる前に管理したよりも良い変換を行うことにかなり近づきましたが、冷酷な事実は、ファイルが適切な状態にないということですpentaho によって確実に処理されます。

これに、私が書いたいくつかの C# をドラッグして、これらのテキスト ファイルでいっぱいのフォルダーを取得し、それらをフラット化された CSV に変換しました。

結果として得られる CSV は完璧ではなく、まだ微調整が必​​要ですが、99.9% の方法で取得できます。結果のファイルは、ソース ファイル自体よりも pentaho を使用して処理する方がはるかに簡単です。

コードはかなり一般的な C# であるため、Windows と Mono の両方でコンパイルする必要があります (認めざるを得ませんが、後者ではテストしていません)。

コードは次のとおりです。

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);
        }
      }

    }
  }
}

ファイルをコンパイルし、結果の EXE をすべての txt ファイルがあるフォルダーにコピーして実行します。

ここで、C# の純粋主義者がここに飛び込んで私のコードの誤りを指摘する前に、これに注意してください...

A) これは、私が抱えていた問題を解決するための迅速なツールとして、少し前に書かれたものであり、製品コードを意図したものではありませんでした。

B)はい、文字列ビルダーと連結など、より良い方法があることを知っています。ポイントAを参照してください

C)あなたが入ってきて、私のコードで障害を拾い始めた場合、(私が持っているように)OPの問題を解決しようとする代わりに、あなたは何もすることがないただのダッチバッグです.

D) 率直に言って、私は気にしないので、あなたが私のコードで指摘しようとするどんな欠点も、私が睡眠を失う結果にはなりません。それは機能します、私はそれが機能することを知っています(その時点で必要だったので)、それが私が気にかけているすべてです。

OPの質問に戻ります。

私が言うように、これは完璧ではありません。最小限の編集を行う必要があります。

必要な編集はすべて、プレーン テキスト エディタを使用して行う必要があります。メモリが不足している場合は、記述行の一部が恐ろしく長く、Excel で使用可能な最大列幅を超えるため、「###」という行になります。 ################'

もちろん、pentaho を使用して CSV をデータベースに直接インポートし、そこにあるレコードを編集してデータを整理することもできます (それが私が行った方法です)。

最後に注意すべき点として、著者名 (または少なくとも複数の名前がある場合) は | を使用して結合されます。文字を「AU」タグの下の1つのCSVフィールドに追加するため、それらをさらに処理する場合は、それらを独自のテーブルに配置し、ソースレコードを指す独自のIDと外部キーで非正規化することを検討してください。 .

コンパイルできない場合 (またはコンパイルしたくない場合) は、お使いのプラットフォームを教えてください。ビルドしてバイナリをお送りします。

于 2013-01-29T00:16:05.300 に答える
3

行を非正規化するには、RowDenormaliserステップを使用する必要があります。

手順:

  1. テキストファイル入力を使用して、データを1つのフィールドに読み込みます

  2. フィールドスプリッターを使用して、「-」のフィールドを分割します

  3. グループフィールドでデータを並べ替えます(サンプルでグループIDを特定しませんでした)。使用可能なグループIDがない場合は、グループごとの行数が固定されているといいのですが、計算されたグループIDを追加できます。

  4. 行を行ノーマライザーに渡し、以下を指定します。

    4.1。グループIDフィールドをグループIDのグループID仕様に追加します。

    4.2。フィールドに必要な各行のターゲットフィールド名を追加します。サンプル
    にTY、T1、JFなどから11を追加しました。これらは任意の名前にすることができます。

    4.3。
    新しいフィールドごとに、分割の結果として2番目のフィールドに割り当てたフィールドの値フィールド名を指定します。フィールドスプリッターのサンプルでは、​​fld_hdrとfld_contentの2つのフィールドを割り当てました。私の値フィールドにはfld_contentfldが含まれています。

    4.4。フィールドタイプと、オプションで各行の残りの列を指定します。

サンプルを作成しましたが、ktrファイルをアップロードする場所がわかりません。

于 2013-01-27T01:18:32.143 に答える