【问题标题】:Replace character of a particular line with incremental number per line [duplicate]用每行递增的数字替换特定行的字符[重复]
【发布时间】:2020-12-19 15:43:07
【问题描述】:

我有一个包含以下几行的文本文件 (data.txt)

# one
# two
a-two
b-two
c-two
# three
a-three
b-three
# four

我想将 # 替换为每行递增的数字,以便像这样

1 one
2 two
a-two
b-two
c-two
3 three
a-three
b-three
4 four

我已经尝试过这样做

    <?php
    $path_to_file = 'data.txt';
    $what_to_replace = '#';
    $i = 0; // initial count
    
    $file_contents = file_get_contents($path_to_file);
    $file_contents = str_replace($what_to_replace, $i++,$file_contents);
    file_put_contents($path_to_file,$file_contents);
    ?>

它确实在所有带有# 的行中都发生了变化,但不是增量的

【问题讨论】:

标签: php


【解决方案1】:

这里有一个简单的方法,通过preg_replace_callback()

$i = 1;
$file_contents = preg_replace_callback('/^#/m', function($match) use (&$i) {
    return $i++;
}, $file_contents);

m(多行)标志很重要 - 它会强制我们的模式在 任何 行的开头匹配 #,而不仅仅是第一行。

【讨论】:

  • (\w+) 不是必需的
  • 额外的清晰度当然没有坏处
【解决方案2】:

我认为您必须遍历所有行并一一替换散列。当然,你也可以使用一些 preg_replace 来只替换行首的#:https://www.php.net/manual/en/function.preg-replace.php

$result = '';
$handle = fopen("data.txt", "r");
$i = 1;
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $content .= str_replace('#', $i++,$line) . "\n";
    }

    fclose($handle);
} else {
    // error opening the file.
}

file_put_contents('data.txt', $result);

【讨论】:

  • 这可能会替换一行中的所有#。它不知道# 的位置,也无法限制它在一行中进行的替换次数。虽然这可能适用于示例输入,但不适用于一般用例。
【解决方案3】:
$path_to_file = 'data.txt';
$what_to_replace = '#';
$i = 1; // initial count

$file_contents = file_get_contents($path_to_file);

$lines = explode(PHP_EOL, $file_contents);
$new_lines = [];

foreach ($lines as $line) {
  if (strpos($line, '#') !== false) {
    $new_lines[] = str_replace('#', $i, $line);
    $i++;
  } else {
    $new_lines[] = $line;
  }
}

file_put_contents($path_to_file, implode(PHP_EOL, $new_lines));

【讨论】:

  • 这可能会替换排位赛中的所有#。它无法限制它在一行中进行的替换次数。虽然这可能适用于样本输入,但不适用于一般用例。这个答案缺少它的教育解释。我不会在我自己的项目中使用这个 sn-p,因为它会进行多次迭代函数调用并在生成变异字符串之前声明一个临时数组——这对我来说太间接了。
  • 是的,哈哈,这里没有争论
【解决方案4】:

我们可以逐行拆分文本,然后单独处理每一行,在行首查找 # 并在这些情况下修改输出。
preg_replace_callback 方法比这个更好,IMO。

$text = file_get_contents(...);
$lines = explode("\n", $text); // split by unix-style line break 
$out = []; // For storing the modified lines
$i=0;
foreach ($lines as $line){
    if (substr($line,0,1)=='#'){
        //replace the first character & increment the counter if line starts with #
        $i++;
        $line = $i.substr($line,1);
    }
    //append the SOMETIMES modified line to the output
    $out[] = $line;
}
// convert array of lines to string
$fixedText = implode("\n", $out);

请参阅 https://stackoverflow.com/a/28725803/802469 以获取更强大的 explode("\n", $text) 行版本。

就个人而言,我喜欢$out = []; ...; implode(...) 方法。我发现使用 & 在我的脑海中形象化更容易。使用$out = ""; $out .= $line."\n"; 方法也可以。我怀疑使用字符串带来的任何性能提升都可以忽略不计,但可能会稍微降低您的碳足迹。

如果您有严重的性能/资源问题(非常大的文件),那么fopen()/while fgets() 方法会更好,fopen/fwrite() 可用于将每个输出行附加到文件中,而不会占用输出字符串的内存。

【讨论】:

  • @mickmackusa,我完全同意。感谢您指出。 :) Iiii 觉得当我写完代码 sn-p 时我有点懒惰了,哈哈。现在更新了!
猜你喜欢
  • 2015-01-26
  • 2022-01-05
  • 2017-03-02
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 2021-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多