PHP의 문자열에서 각 행에 걸쳐 반복
사용자가 텍스트 파일을 업로드하거나 파일 내용을 텍스트 영역에 복사/붙일 수 있는 양식을 가지고 있습니다.이 둘을 쉽게 구별할 수 있고 문자열 변수에 입력한 것을 넣을 수 있습니다. 하지만 여기서부터는 어떻게 해야 할까요?
문자열의 각 행에 대해 반복해야 합니다(가능하면 서로 다른 머신에서 새로운 행에 대해 걱정하지 않는 것이 좋습니다). 토큰이 1개(스페이스, 탭, 쉼표 등)인지 확인하고 데이터를 삭제한 다음 모든 행에서 SQL 쿼리를 생성해야 합니다.
저는 프로그래머를 꽤 잘하기 때문에 일반적인 방법은 알고 있습니다만, PHP를 사용한 지 너무 오래되어 잘못된 것을 찾고 있기 때문에 불필요한 정보를 얻을 수 있습니다.제가 안고 있는 중요한 문제는 문자열의 내용을 한 줄 한 줄 읽고 싶다는 것입니다.그게 파일이었다면 쉬웠을 거야
저는 주로 유용한 PHP 함수를 찾고 있습니다. 방법을 위한 알고리즘이 아닙니다.좋은 의견이라도 있나?
preg_split
텍스트를 포함하는 변수와 반환된 배열에 대해 반복합니다.
foreach(preg_split("/((\r?\n)|(\r\n?))/", $subject) as $line){
// do stuff with $line
}
상당히 빠른(및 메모리 효율이 뛰어난) 대안을 제안하고 싶습니다.strtok
보다는preg_split
.
$separator = "\r\n";
$line = strtok($subject, $separator);
while ($line !== false) {
# do something with $line
$line = strtok( $separator );
}
성능을 테스트하면서 17,000줄의 테스트 파일을 100회 반복했습니다.preg_split
27.7초 걸린 반면strtok
1.4초 걸렸어요
주의해 주세요.$separator
로 정의됩니다."\r\n"
,strtok
는, 어느 쪽인가의 문자로 구분됩니다.PHP 4.1.0 에서는, 빈 행/토큰을 건너뜁니다.
strtok 수동 엔트리를 참조해 주세요.http://php.net/strtok
다른 시스템에서 새로운 라인을 처리해야 할 경우 PHP의 사전 정의된 상수 PHP_EOL(http://php.net/manual/en/reserved.constants.php)을 사용하고 정규 표현 엔진의 오버헤드를 피하기 위해 폭발을 사용할 수 있습니다.
$lines = explode(PHP_EOL, $subject);
너무 복잡하고 추하지만 제 생각에는 이렇게 하는 게 좋을 것 같아요.
$fp = fopen("php://memory", 'r+');
fputs($fp, $data);
rewind($fp);
while($line = fgets($fp)){
// deal with $line
}
fclose($fp);
잠재적인 메모리 문제strtok
:
제안된 솔루션 중 하나가strtok
그러나 유감스럽게도 메모리 효율적이라고는 하지만 잠재적인 메모리 문제를 지적하지는 않습니다.사용시strtok
설명서에 따르면:
strtok 에 대한 첫 번째 콜만이 string 인수를 사용하는 것에 주의해 주세요.이후 strtok에 콜할 때마다 토큰을 사용해야 합니다.이는 현재 문자열 내의 위치를 추적하기 때문입니다.
이것은, 파일을 메모리에 로드하는 것에 의해서 행해집니다.대용량 파일을 사용하는 경우 파일 루핑이 끝나면 파일을 플러시해야 합니다.
<?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.
}
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
Kyril의 답변은 당신이 다른 기계에서 새로운 라인을 다룰 수 있어야 한다는 것을 고려할 때 가장 적합합니다.
"저는 주로 유용한 PHP 함수를 찾고 있습니다. 방법을 위한 알고리즘이 아닙니다.제안해 주실 수 있나요?
저는 이걸 많이 써요.
- plaste()는 단일 딜리미터를 지정하면 문자열을 배열로 분할할 수 있습니다.
- innode()는 배열에서 문자열로 되돌리기 위한 폭발 대응어입니다.
@pguardiario와 비슷하지만 좀 더 "모던" (OOP) 인터페이스를 사용합니다.
$fileObject = new \SplFileObject('php://memory', 'r+');
$fileObject->fwrite($content);
$fileObject->rewind();
while ($fileObject->valid()) {
$line = $fileObject->current();
$fileObject->next();
}
- SplFileObject 문서: https://www.php.net/manual/en/class.splfileobject.php
- PHP IO 스트림: https://www.php.net/manual/en/wrappers.php.php
언급URL : https://stackoverflow.com/questions/1462720/iterate-over-each-line-in-a-string-in-php
'programing' 카테고리의 다른 글
변경 전 선택(드롭다운) 값을 가져오는 중 (0) | 2022.09.11 |
---|---|
어레이에 값을 추가하는 가장 효율적인 방법 (0) | 2022.09.11 |
MySQL의 DATETIME 필드에서 날짜만 선택하는 방법 (0) | 2022.09.11 |
Vue는 생성자가 아닙니다. (0) | 2022.09.11 |
프라이머리 SQL별 FIFO 값 감소 (0) | 2022.09.11 |