そのテキストサンプルはひどく見覚えがあります.....
急いで何かを確認する
そのテキスト サンプルが「王立科学協会ジャーナル記述ファイル」であると私が考えるものである場合、これらを解析するペンタホ スクリプトを作成することはできません。
私はそこに行って試してみましたが、とても苦痛でした。
なんで?
まあいろいろ。
まず、ファイル形式は厳密にチェックされていないため、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と外部キーで非正規化することを検討してください。 .
コンパイルできない場合 (またはコンパイルしたくない場合) は、お使いのプラットフォームを教えてください。ビルドしてバイナリをお送りします。