在 PHP 中迭代字符串中的每一行

我有一个表单,允许用户上传文本文件或复制/粘贴文件的内容到一个文本区。我可以很容易地区分两者,并把他们输入的任何一个字符串变量,但我从那里去?

我需要遍历字符串的每一行(最好不要担心不同机器上的换行) ,确保它只有一个标记(没有空格、制表符、逗号等) ,清理数据,然后根据所有行生成一个 SQL 查询。

我是一个相当优秀的程序员,所以我知道如何做到这一点的一般想法,但它是如此长的时间,因为我与 PHP 工作,我觉得我正在寻找错误的东西,因此提出了无用的信息。我遇到的关键问题是我想逐行读取字符串的内容。如果是文件的话,就简单多了。

我主要是寻找有用的 PHP 函数,而不是一个算法如何做到这一点。有什么建议吗?

161069 次浏览

preg_split包含文本的变量,并在返回的数组上迭代:

foreach(preg_split("/((\r?\n)|(\r\n?))/", $subject) as $line){
// do stuff with $line
}

Kyril 的答案是最好的,因为您需要能够在不同的机器上处理换行。

“我主要是在寻找有用的 PHP 函数,而不是一个如何 有什么建议吗?”

我经常用这个:

如果你需要在不同的系统中处理换行符,你可以简单地使用 PHP 预定义的常量 PHP _ EOL ( http://PHP.net/manual/en/reserved.constants.PHP ) ,并简单地使用  爆炸来避免正则表达式引擎的开销。

$lines = explode(PHP_EOL, $subject);

我想提出一个 意义重大更快(和内存效率)的替代方案: strtok而不是 preg_split

$separator = "\r\n";
$line = strtok($subject, $separator);


while ($line !== false) {
# do something with $line
$line = strtok( $separator );
}

测试性能时,我在一个有17000行的测试文件上迭代了100次: preg_split用了27.7秒,而 strtok用了1.4秒。

请注意,虽然 $separator被定义为 "\r\n",但是 strtok将在任何一个字符上分开——从 PHP4.1.0开始,跳过空行/标记。

参见 strtok 手动输入: Http://php.net/strtok

它过于复杂和丑陋,但在我看来,这是应该走的路:

$fp = fopen("php://memory", 'r+');
fputs($fp, $data);
rewind($fp);
while($line = fgets($fp)){
// deal with $line
}
fclose($fp);
foreach(preg_split('~[\r\n]+~', $text) as $line){
if(empty($line) or ctype_space($line)) continue; // skip only spaces
// if(!strlen($line = trim($line))) continue; // or trim by force and skip empty
// $line is trimmed and nice here so use it
}

^ 这才是正确的分界线,跨平台兼容 Regexp:)

strtok可能存在的内存问题:

由于其中一个建议的解决方案使用 strtok,不幸的是它没有指出潜在的内存问题(尽管它声称是内存高效的)。根据 手册使用 strtok时,应:

注意,只有对 strtok 的第一个调用使用字符串参数。 对 strtok 的每个后续调用都只需要使用标记,< strong > as it 跟踪它在当前字符串中的位置

它通过将文件加载到内存中来实现这一点。 如果您使用的是大型文件,那么如果您已经完成了文件循环,则需要刷新它们。

<?php
function process($str) {
$line = strtok($str, PHP_EOL);


/*do something with the first line here...*/


while ($line !== FALSE) {
// get the next line
$line = strtok(PHP_EOL);


/*do something with the rest of the lines here...*/


}
//the bit that frees up memory
strtok('', '');
}

如果你只关心物理文件(例如数据挖掘) :

根据手册 ,对于文件上传部分,可以使用 file命令:

 //Create the array
$lines = file( $some_file );


foreach ( $lines as $line ) {
//do something here.
}

与@pguardiario 类似,但使用更“现代”(OOP)的接口:

$fileObject = new \SplFileObject('php://memory', 'r+');
$fileObject->fwrite($content);
$fileObject->rewind();


while ($fileObject->valid()) {
$line = $fileObject->current();
$fileObject->next();
}