【问题标题】:PHP : How to Replace some text from n th line to m th line from file?PHP:如何将文件中第 n 行的某些文本替换为第 m 行?
【发布时间】:2018-04-14 18:33:27
【问题描述】:

我有一个像 some.txt 这样的文件,里面有内容:

#start-first
Line 1
Line 2
Line 3
#end-first

#start-second
Line 1
Line 2
Line 3
Line 4
#end-second

#start-n
Line 1
Line 2
Line 3
Line 4
...
...
#end-n

我想从#start-second#end-second 或从#start-n#end-n 删除文件中的内容,实际上#start-second开始标记 用于第二个文本块 文件,#end-second 是文件第二个文本块结束标记

如何将特定起始块的内容删除到同一个结束块?

【问题讨论】:

  • 您不能从文件中“删除”每行的内容。把字节都弄乱了(我试过了,一旦效果不好)。您可以逐行阅读,只是不要将这些行放在新的“副本”中
  • 如果你的系统是linux,可以使用sed,非常好用
  • @SNTiwari - 仍然没有“删除”它的read/overwrite 抱歉,我总是默认为 80mb 或更多文件。习惯于与它们打交道,(即如果它很大,可能会在内存上很粗糙)
  • ya 替换,谢谢@ArtisticPhoenix

标签: php file fopen fwrite


【解决方案1】:

如果这些文件真的很大,有一个相当轻量级的解决方案:

$file = file_get_contents("example.txt");
// Find the start "#start-$block", "#end-$block" and the length between them:
$start = strpos($file, "#start-$block");
$end = strpos($file, "#end-$block");
$length = $end-$start+strlen("#end-$block");

$file = substr_replace($file, '', $start, length);
file_put_contents("example.txt", $file);

我最初的答案是从一个正则表达式开始的:

$block = 4;

// Open the file
$file = openfile("example.txt");

// replace #start-$block, #end-$block, and everything inbetween with ''
$file = preg_replace("/#start\-".$block."(?:.*?)#end\-".$block."/s", '', $file);

// Save the changes
file_put_contents("example.txt", $file);

虽然正则表达式很昂贵,但有时更容易理解。

【讨论】:

  • 我可以用fopen()做吗
  • 为什么要专门使用 fopen()?
  • 只是为了知识!
  • 也许有一个使用 fopen 的解决方案,但我不知道有一个。我喜欢 file_get/put_contents。
【解决方案2】:

这是我的解决方案:

逐行执行此操作有点困难,但它确实可以让您更好地管理大文件的内存,因为您不会一次打开整个文件。您也可以通过这种方式更轻松地替换多个块。

$file = 'test.txt';
//open file to read from
$f = fopen(__DIR__.DIRECTORY_SEPARATOR.$file,'r');
//open file to write to
$w = fopen(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file,'w');

$state = 'start';  //start, middle, end

//start - write while looking for a start tag ( set to middle )
//middle - skip while looking for end tag  ( set to end )
//end - skip while empty ( set to start when not )

//Tags
$start = ['#start-second'];
$end = ['#end-second'];

 //read each line from the file
while( $line = fgets($f)){     
    if( $state == 'end' && !empty(trim($line))){
        //set to start on first non empty line after tag
        $state = 'start';
    }

    if( $state == 'start' ){
        if(in_array(trim($line),$start)){
            $state = 'middle';
        }else{
            fwrite($w, $line);
        }
    }else if( $state == 'middle' ){
        if(in_array(trim($line),$end)){
            $state = 'end';
        }
    }   
}
//close both files
fclose($f);
fclose($w);

//delete the input file
//unlink(__DIR__.DIRECTORY_SEPARATOR.$file);

//for debugging only
echo "<pre>";
echo file_get_contents(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file)

还有输出

#start-first
Line 1
Line 2
Line 3
#end-first

#start-n
Line 1
Line 2
Line 3
Line 4
...
...
#end-n

这也将接受一组标签,因此您可以每次删除多个块。

出于安全原因,大多数 PHP 沙箱(或一般的代码沙箱)会阻止您使用这些函数。也就是说,在某种程度上,我们可以emulate 代码主体,解析位。这就是我在这里所做的。

http://sandbox.onlinephpfunctions.com/code/0a746fb79041d30fcbddd5bcb00237fcdd8eea2f

这样你就可以尝试几个不同的标签,看看它是如何工作的。为了获得额外的功劳,您可以将其变成一个接受文件路径和一组打开和开始标签的函数。

   /**
   * @var string  $pathName - full path to input file
   * @var string  $outputName - name of output file
   * @var array $tags - array of tags ex. ['start'=>['tag1'],'end'=>[...]]
   * @return string - path to output file
   */
   function($pathName, $outputName, array $tags){
        ....
   }

【讨论】:

    猜你喜欢
    • 2021-10-18
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2018-11-16
    • 2015-11-26
    相关资源
    最近更新 更多