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){
....
}
我有一个类似 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){
....
}