PHP : 如何替换文件中第 n 行到第 m 行的一些文本?

PHP : How to Replace some text from n th line to m th line from file?

我有一个类似 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 第二个文本的 结束标记 文件块

如何删除特定开始块到相同结束块的内容?

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

$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);

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

这是我的解决方案:

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

$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){
        ....
   }