我怎样使用php替换文件中特定行的文本?
我不知道这一行的编号。我想要替换一个包含特定单词的行。
我怎样使用php替换文件中特定行的文本?
我不知道这一行的编号。我想要替换一个包含特定单词的行。
如果文件大小较小,可以采用一种方法,将其存储在内存中两次:
$data = file('myfile'); // reads an array of lines
function replace_a_line($data) {
if (stristr($data, 'certain word')) {
return "replacement line!\n";
}
return $data;
}
$data = array_map('replace_a_line', $data);
file_put_contents('myfile', $data);
快速提醒,PHP > 5.3.0 支持 lambda 函数,因此您可以删除命名函数声明并将 map 缩短为:
$data = array_map(function($data) {
return stristr($data,'certain word') ? "replacement line\n" : $data;
}, $data);
file_put_contents('myfile', implode('',
array_map(function($data) {
return stristr($data,'certain word') ? "replacement line\n" : $data;
}, file('myfile'))
));
对于较大的文件,您应该使用另一种(内存占用较少)方法:
$reading = fopen('myfile', 'r');
$writing = fopen('myfile.tmp', 'w');
$replaced = false;
while (!feof($reading)) {
$line = fgets($reading);
if (stristr($line,'certain word')) {
$line = "replacement line!\n";
$replaced = true;
}
fputs($writing, $line);
}
fclose($reading); fclose($writing);
// might as well not overwrite the file if we didn't replace anything
if ($replaced)
{
rename('myfile.tmp', 'myfile');
} else {
unlink('myfile.tmp');
}
fclose()
之后太快运行rename()
时出现"access denied"代码5错误,我不得不对两个处理器进行fseek()
操作,并使用stream_copy_to_stream()
进行复制,然后关闭处理器。 - Leopoldo Sanczykstrstr()
函数来检查字符串在另一个字符串中的存在性,而应该使用更高效的strpos()
函数来完成此任务。 - mickmackusa您还可以使用正则表达式的多行模式
preg_match_all('/word}/m', $textfile, $matches);
当然,这是假设文档较小而且已准备好并加载的情况。否则,其他答案将更加符合“实际应用”的解决方案。
}
除了让研究人员感到困惑之外,还有什么作用吗?对于给定的模式,m
标志是无用的,它不会影响任何东西。我不明白这个答案获得的分数是怎么来的。这看起来像一个优秀的“遵纪守法”徽章候选者。 - mickmackusastrpos
和str_replace
的组合来查找单词,或者使用preg_replace
。strpos
返回FALSE时替换该行,并将文件保存回磁盘即可。$filedata = file('filename');
$newdata = array();
$lookfor = 'replaceme';
$newtext = 'withme';
foreach ($filedata as $filerow) {
if (strstr($filerow, $lookfor) !== false)
$filerow = $newtext;
$newdata[] = $filerow;
}
现在$newdata
包含文件内容的数组(如果不想使用数组,请使用implode()
),其中包含“replaceme”的行已替换为“withme”。
strstr()
函数来检查字符串在另一个字符串中的存在性,而应该使用更高效的strpos()
函数来完成此任务。 - mickmackusa如果你正在查找一行中的子字符串(ID),并希望用新的替换旧的,这种方法非常适合。
代码:
$id = "123";
$new_line = "123,Programmer\r"; // We're not changing the ID, so ID 123 remains.
$contents = file_get_contents($dir);
$new_contents= "";
if( strpos($contents, $id) !== false) { // if file contains ID
$contents_array = preg_split("/\\r\\n|\\r|\\n/", $contents);
foreach ($contents_array as &$record) { // for each line
if (strpos($record, $id) !== false) { // if we have found the correct line
$new_contents .= $new_line; // change record to new record
}else{
$new_contents .= $record . "\r";
}
}
file_put_contents($dir, $new_contents); // save the records to the file
echo json_encode("Successfully updated record!");
}
else{
echo json_encode("failed - user ID ". $id ." doesn't exist!");
}
示例:
旧文件:
ID,职业
123,学生
124,砖层工人
运行代码将更改文件为:
新文件:
ID,职业
123,程序员
124,砖层工人
\\r\\n|\\r|\\n
可以完全被 \R
替换。我不会使用 $record . "\r"
。 - mickmackusaexplode();
函数将文件转换为数组,编辑数组中的任何项,使用implode();
函数将数组转换回字符串,然后您可以使用file_put_contents();
函数将字符串放回文件中。以下是示例函数:function file_edit_contents($file_name, $line, $new_value){
$file = explode("\n", rtrim(file_get_contents($file_name)));
$file[$line] = $new_value;
$file = implode("\n", $file);
file_put_contents($file_name, $file);
}
file()
而不是explode(file_get_contents())
。更重要的是,原帖明确说明:“_我不知道行号_”。 - mickmackusa或许这可以帮助:
$data = file("data.php");
for($i = 0;$i<count($data);$i++){
echo "<form action='index.php' method='post'>";
echo "<input type='text' value='$data[$i]' name='id[]'><br>";
}
echo "<input type='submit' value='simpan'>";
echo "</form>";
if(isset($_POST['id'])){
file_put_contents('data.php',implode("\n",$_POST['id'])) ;
}
这个函数应该替换文件中的一整行:
function replace($line, $file) {
if ( file_get_contents($file) == $line ) {
file_put_contents($file, '');
} else if ( file($file)[0] == $line.PHP_EOL ) {
file_put_contents($file, str_replace($line.PHP_EOL, '', file_get_contents($file)));
} else {
file_put_contents($file, str_replace(PHP_EOL.$line, '', file_get_contents($file)));
}
}
第一个if
语句(第2行)检查要删除的行是否是唯一的行。然后它清空文件。第二个if
语句(第4行)检查要删除的行是否是文件中的第一行。如果是,则使用str_replace($line.PHP_EOL, '', file_get_contents($file))
来删除该行。 PHP_EOL
是一个新行符,因此这将删除行内容,然后删除行尾换行符。最后,else
语句仅在要删除的行不是唯一内容且不在文件开头时才会被调用。然后再次使用str_replace
,但这次使用PHP_EOL.$line
而不是$line.PHP_EOL
。这样,如果该行是文件的最后一行,则会在其前面删除换行符,然后删除该行。
用法:
replace("message", "database.txt");
如果存在包含message
的行,则从文件database.txt
中删除该行。如果您想缩短代码,可以尝试以下方法:
function replace($line,$file){if(file_get_contents($file)==$line){file_put_contents($file,'');}else if(file($file)[0]==$line.PHP_EOL){file_put_contents($file,str_replace($line.PHP_EOL,'', file_get_contents($file)));}else{file_put_contents($file,str_replace(PHP_EOL.$line,'',file_get_contents($file)));}}
希望这回答了你的问题 :)
file()
——它将从每一行文本完全填充一个数组——只是为了读取第一行并不是性能最优的选择。与其将代码拼凑在一起使其“更短”(更难读懂),不如编写变量来保存被多次访问的值。DRY代码是好代码。 - mickmackusa如果您在处理文件时不打算 锁定文件,那么
话虽如此,为了速度而牺牲准确性是没有意义的。这个问题说明必须在行中匹配一个单词。因此,必须防止部分匹配 - 正则表达式提供了单词边界 (\b
)。
$filename = 'test.txt';
$needle = 'word';
$newText = preg_replace(
'/^.*\b' . $needle . '\b.*/mui',
'whole new line',
file_get_contents($filename)
1,
$count
);
if ($count) {
file_put_contents($filename, $newText);
}
模式:
/ #starting pattern delimiter
^ #match start of a line (see m flag)
.* #match zero or more of any non-newline character
\b #match zero-width position separating word character and non-word character
word #match literal string "word"
\b #match zero-width position separating word character and non-word character
.* #match zero or more of any non-newline character to end of line
/ #ending pattern delimiter
m #flag tells ^ character to match the start of any line in the text
u #flag tells regex engine to read text in multibyte modr
i #flag tells regex engine to match letters insensitively
如果使用不区分大小写的搜索,但需要在替换字符串中使用实际匹配的单词,请在模式中括号中写入针,然后在替换字符串中使用$1
。