2011-12-15 12 views
1

ので、私のファイルは次のようになります。このファイル操作はどのようにしてperlで行いますか?

--some comments-- 
--a couple of lines of header info-- 
comp: 
    name: some_name_A 
    type: some_type 
    id: an id_1 
    owner: who owns it 
    path: path_A to more data 
end_comp 

comp: 
    name: some_name_B 
    type: some_type 
    id: an id_2 
    owner: who owns it 
    path: path_B to more data 
end_comp 

私はを何をしたいか:名前フィールドから名前を取得し、それは我々が検索したい名前のいずれかと一致するかどうかを確認(すでに配列で提供)、パスを取得した後、そのパスに行き、いくつかの力を行使して新しいidを取得し、現在のidを新しいidに置き換えます。

は私が(ちょうど擬似)を行っている:

@filedata = <read_file> #read file in an array 
$names_to_search = join("|", @some_names); 

while([email protected]) 
{ 
if($line =~ /comp:/) 
{ 
    $line = <next line>; 
    if($line =~ /name: $names_to_search/) 
    { 
    #loop until we find the id 
    #remember this index since we need to change this id 

    #loop until we find the path field 
    #get the path, go to that path, do some perforce commands and obtain new id 
    if(id is same as current id) no action required 
    else replace current id with new id 
    } 
    } 
} 

問題:私の現在の実装では、whileループ3のように持っています!これを行うにはより良い/効率的/優雅な方法がありますか?

+0

ファイルに 'name'と同じ値を持つ2つのブロックがありますか? –

+0

@JackManey、Nope :) – infinitloop

答えて

4

設定ファイルをカスタム形式で作成し、手動で解析しようとしました。代わりに、YAMLやINIのような確立された形式でファイルを書いて、それを解析するために既存のモジュールを使用しないでください。例えば

、YAML使用して:あなたはConfig::INIまたはConfig::INI::SimpleでINIファイルを読み取ることができ

use YAML::Any; 
my @data = YAML::Any::LoadFile($filename) or die "Could not read from $filename: $!": 

# now you have your data structure in @data; parse it using while/for/map loops. 

を。ここで

+0

多くの人が提案するように、私はxml形式で記述し、Perlのxmlパーサを使用します。 :) – infinitloop

1

は、いくつかの擬似コードです:

index = 0; 

index_of_id = 0; // this is the index of the line that contains the current company id 

have_company = false; // track whether we are processing a copmany 

while (line in @filedata) 
{ 
    if (!have_company) 
    { 
    if (line is not "company") 
    { 
     ++index; 
     continue; 
    } 
    else 
    { 
     index_of_id = 0; 
     have_company = true; 
    } 
    } 
    else 
    { 
    if (line is "end_comp") 
    { 
     have_company = false; // force to start looking for new company 
     ++index; 
     continue; 
    } 

    if (line is "id") 
     index_of_id = index; // save the index 

    if (line is "path") 
    { 
     // do your stuff then replace the string at the index given by index_of_id 
    } 
    } 
    // line index 
    ++index; 
} 

// Now write the modified array to file 
1

何の2つのブロックが同じname値を持つことはできませんので、あなたはハッシュリファレンスのハッシュリファレンスを使用することができます。このような

{ 
    "name1"=>{type=>"type1",id=>"id1",owner=>"owner1",path=>"path1"}, 
    "name2"=>{type=>"type2",id=>"id2",owner=>"owner2",path=>"path2"}, 
    #etc 
} 

何か作業をする必要があります(警告:未テスト):

use strict; 
use warnings; 

open(my $read,"<","input_file.txt") or die $!; 

my $data={}; 
my $current_name=""; #Placeholder for the name that we're currently using. 

while(<$read>) 
{ 
    chomp; #get rid of trailing newline character. 

    if(/^\s*name:\s*([\w]+)\s*$/) #If we hit a line specifying a name, 
           #then this is the name we're working with 
    { 
    $current_name=$1; 
    } 
    elsif(/^\s*(type|id|owner|path):\s*([\w]+)\s*$/) #If it's data to go with the name, 
                #then assign it. 
    { 
    $data->{$current_name}->{$1}=$2; 
    } 
} 

close($read); 

#Now you can search your given array for each of the names and do what you want from there. 

ただし、可能であれば、私は(YAML、INI、JSON、XMLなど)標準化された形式でファイルにデータを格納し、それを適切に解析します。また、このコードは、対応するtypeidownerおよびpathより前に現れるそれぞれのnameに依存することを付け加えておきます。

関連する問題