我如何在 perl 中进行文件操作?

发布于 2024-12-21 07:59:16 字数 1154 浏览 0 评论 0原文

所以我的文件如下所示:

--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,前提是它与当前 id 不同。

我所做的(只是伪):

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

while(lines=@filedata)
{
 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 循环!有没有更好/高效/优雅的方法来做到这一点?

so my file looks like this:

--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  

What I want to do: Get the name from the name field and see if it matches one of the names we want to search (already provided in an array), after that get the path, go to that path, do some perforce stuff and obtain new id, then replace the current id with the new id, only if it is different then current one.

What I have done (just a pseudo):

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

while(lines=@filedata)
{
 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
   }
  }
}

The problem: My current implementation has like three while loops! Is there a better/efficient/elegant way of doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

⊕婉儿 2024-12-28 07:59:16

您已经以自定义格式编写了一个配置文件,然后尝试手动解析它。相反,为什么不以 YAML 或 INI 等既定格式编写文件,然后使用现有模块来解析它呢?

例如,使用 YAML:

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.

您可以使用 Config::INI 读取 INI 文件或Config::INI::Simple

You've written a config file in a custom format, and then attempting to parse it manually. Instead, why not write the file in an established format such as YAML or INI, and then use existing modules to parse it?

For example, using YAML:

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.

You can read INI files with Config::INI or Config::INI::Simple.

尐偏执 2024-12-28 07:59:16

这是一些伪代码:

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

Here is some pseudocode:

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
旧人九事 2024-12-28 07:59:16

由于没有两个块可以具有相同的 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之前的每个 name代码>路径。

Since no two blocks can have the same name value, you can use a hash reference of hash references:

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

Something like this should work (Warning: Untested):

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.

However, if you can, I'd really recommend storing the data in your file in some kind of standardized format (YAML, INI, JSON, XML, etc) and then parsing it appropriately. I should also add that this code depends on each name appearing before the corresponding type, id, owner and path.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文