PHP에서 문자열의 각 줄을 반복


130

사용자가 텍스트 파일을 업로드하거나 파일 내용을 텍스트 영역에 복사 / 붙여 넣을 수있는 양식이 있습니다. 두 가지를 쉽게 구별하고 문자열 변수에 입력 한 것을 넣을 수는 있지만 어디로 가야합니까?

문자열의 각 줄을 반복하고 (바람직하게는 다른 컴퓨터의 줄 바꿈에 대해 걱정하지 않아야 함) 정확히 하나의 토큰 (공백, 탭, 쉼표 등 없음)이 있는지 확인하고 데이터를 삭제 한 다음 SQL 쿼리를 생성해야합니다 모든 라인을 기반으로합니다.

나는 꽤 좋은 프로그래머이므로 그것을하는 방법에 대한 일반적인 아이디어를 알고 있지만 PHP로 작업한지 너무 오래되어 잘못된 것을 찾고 있다고 생각하여 쓸모없는 정보가 떠 오릅니다. 내가 가지고있는 주요 문제는 문자열의 내용을 한 줄씩 읽고 싶다는 것입니다. 파일이라면 쉬울 것입니다.

나는 주로 유용한 PHP 함수를 찾고 있는데, 그 방법에 대한 알고리즘이 아닙니다. 어떤 제안?


개행을 먼저 정규화 할 수 있습니다. 이 방법 s($myString)->normalizeLineEndings()은 다른 유용한 문자열 도우미가 많은 github.com/delight-im/PHP-Str (MIT 라이센스 하의 라이브러리)에서 사용할 수 있습니다 . 소스 코드를 살펴볼 수 있습니다.
caw

답변:


190

preg_split 텍스트가 포함 된 변수를 반환하고 반환 된 배열을 반복합니다.

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

\ n \ r 외에도 ^ M을 처리합니까?
Topher Fangio

변수 캐리지 반환 후 ascii 캐리지 리턴이 \ r로 변환되는지 확실하지 않습니다. 그렇지 않다면 항상 ascii 값으로 split () / exlope ()을 사용할 수 있습니다-ch (13)
Kyril

12
더 나은 정규식은 /((\r?\n)|(\r\n?))/입니다.
Félix Saparelli

3
Unix LF (\ n), MacOS <9 CR (\ r), Windows CR + LF (\ r \ n) 및 드문 LF + CR (\ n \ r)과 일치하려면 다음과 같아야합니다./((\r?\n)|(\n?\r))/
Deving for Dev ...

2
이는 멀티 바이트 데이터의 경우 치명적으로 발생할 수 있습니다.
pguardiario

158

내가 제안하고 싶은 크게 : 빠른 (메모리 효율) 대안 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 그리고 PHP4.1.0의 비어 선 / 토큰을 건너 - 중 캐릭터에 분리됩니다.

strtok 매뉴얼 항목을 참조하십시오 : http://php.net/strtok


21
대규모 라인 세트를 처리 할 때 성능을 고려할 경우 +1
CodeAngry

4
이 함수 api는 전체 혼란 (다른 매개 변수를 사용하는 호출)이지만 이것이 가장 좋은 솔루션입니다. 어느 쪽 prey_splitexplode구조화 문자열 단편을 수득 사용되어서는 안된다. 마치 바주카로 비행하는 것을 목표로하는 것과 같습니다 .
Maciej Sz

1
앱이 실행되는 동안 메모리 사용량을 확인하면 마법이 나타납니다. 그것은 실제로 당신이 라인의 각 통해 이벤트 당신 루프에서 메모리에 읽고있는 파일을 끌어 당신의 토큰 위치를 유지합니다. 실제로 메모리를 효율적으로 사용하려면 플러시해야합니다. php.net/strtok#103051
AbsoluteƵERØ

2
루프 strtok()내부의 다른 것을 사용 while하면 문제가 발생합니다. 나는 또한 그것을 사용하여 문자열의 모든 것을 첫 번째 공간 ( stackoverflow.com/a/2477411/1767412 )까지 잡았으며 일이 계획대로 진행되지 않은 이유를 깨닫는 데 잠시 시간이 걸렸습니다
billynoah

1
아마도 모든 옵션 중에서 가장 빠른 해결책 일 것입니다.
John

94

다른 시스템에서 줄 바꿈을 처리 해야하는 경우 단순히 PHP 사전 정의 상수 PHP_EOL (http://php.net/manual/en/reserved.constants.php)을 사용하고 정규 표현식 엔진의 오버 헤드를 피하기 위해 explode를 사용하면됩니다 .

$lines = explode(PHP_EOL, $subject);

30
주의 : 그것은 작동 다른 시스템에 있지만 문자열과 잘 작동하지 않습니다 서로 다른 시스템에서 . PHP 매뉴얼 상태 PHP_EOL (string)입니다 에 대한 기호 올바른 '라인의 끝' 플랫폼입니다.
wadim

@wadim이 맞습니다! Unix 서버에서 Windows 텍스트 파일을 처리하는 경우 실패합니다.
javsmo

1
줄 길이에 따라 큰 줄에 대해 많은 양의 메모리를 사용할 수 있습니다.
Synchro

마지막 줄에 줄 종결자가 포함되어 있으면 그 뒤에 다른 빈 문자열도 반환됩니다.
rightfold

20

지나치게 복잡하고 추악하지만 제 생각에는 이것이 갈 길입니다.

$fp = fopen("php://memory", 'r+');
fputs($fp, $data);
rewind($fp);
while($line = fgets($fp)){
  // deal with $line
}
fclose($fp);

1
+1 및 php://temp더 큰 데이터를 임시 디스크 파일에 저장하는 데 사용할 수도 있습니다 .
CodeAngry

4
이렇게하면 strtok () 솔루션과 달리 빈 줄을 감지 할 수 있습니다. 문서는 php.net/manual/en/…에 있습니다.
Josip Rodin

7
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:)


6

잠재적 메모리 문제 strtok:

제안 된 솔루션 중 하나 strtok가을 사용하기 때문에 불행히도 잠재적 인 메모리 문제를 지적하지는 않습니다 (메모리 효율적이라고 주장하지만). 매뉴얼strtok 에 따라 사용 하는 경우 :

strtok에 대한 첫 번째 호출 만 문자열 인수를 사용합니다. 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('', '');
}

실제 파일에만 관심이있는 경우 (예 : 데이터 마이닝) :

manual에 따르면 파일 업로드 부분에 대해 다음 file명령을 사용할 수 있습니다 .

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

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

4

Kyril의 대답은 다른 컴퓨터에서 줄 바꿈을 처리해야한다는 점을 고려하는 것이 가장 좋습니다.

"저는 유용한 PHP 함수를 찾고 있는데, 그 방법에 대한 알고리즘이 아닙니다. 어떤 제안이 있습니까?"

나는 이것을 많이 사용합니다 :

  • 터지다() 를 사용하면 단일 구분 기호를 사용하여 문자열을 배열로 분할 할 수 있습니다.
  • implode ()는 폭발에서 대응하는 배열로 배열에서 문자열로 돌아갑니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.