2011-01-19 5 views
11

私はPHPのpreg_match_all()を使用して、file_get_contents()を使用してインポートした文字列を検索しています。正規表現は一致を返しますが、それらの一致が見つかった行番号を知りたいと思います。これを達成するための最良の方法は何ですか?preg_match_all()から行番号を取得する

ファイルを配列として読み込んで各行に対して正規表現を実行できますが、問題は正規表現がキャリッジリターン(改行)の結果と一致するということです。

+1

私は推測を捨てに行くと、あなたがすることができないかもしれないと言っていますこのために 'preg_match_all'を使います。 – drudge

+0

結果にpreg_splitとcount行ありますか?私が言ったので、それは今や馬鹿に聞こえる。 – scragz

+0

私はあなたがしたいことを達成するための簡単な方法が表示されません... –

答えて

8

これはちょっと遅れているかもしれませんが、私はこれを解決したかもしれませんが、私はそれを実行しなければならず、かなり簡単です。 preg_matchPREG_OFFSET_CAPTUREフラグを使用すると、一致する文字の位置が返されます。 はそう

list($before) = str_split($content, $charpos); // fetches all the text before the match 

$line_number = strlen($before) - strlen(str_replace("\n", "", $before)) + 1; 

出来上がり、$ charposとさせて頂きます!

10

これは正規表現だけでは実行できません。少なくともきれいではない。 preg_match_allのPREG_OFFSET_CAPTUREフラグを使用して、ファイル全体のポスト解析を行うにはどうすればよいですか。

は、私はあなたがそれぞれの文字列の一致文字列の配列と開始オフセットを持っていた後だけ\r\nまたは\nまたは\rは、ファイルの先頭に、各試合のオフセットの間にあるどのように多くのカウントを意味します。一致の行番号は、別個のEOLターミネータ(\r\n | \n | \r)+ 1の数になります。

1

私は、あなたが各要素は、各ラインのために立って、このように見えるか、配列に$文字列を読み取るために、すべての最初の必要があると思うん:あなたはカップルのオプションを持っている

$List=file($String); 
for($i=0;$i<count($List),$i++){ 
if(preg_match_all()){;//your work here 
echo $i;//echo the line number where the preg_match_all() works 
} 
} 
+0

私はあなたが私の質問のこの部分を逃したと思う:私は配列としてファイルを読むことができると各行の正規表現を実行するが、問題は私の正規表現はキャリッジリターン(改行)の結果にマッチします。 – bart

2

、どれも"シンプル" です:

A)exec()と行番号を報告できるシステムgrepコマンド、使用:

exec("grep -n 'your pattern here' file.txt", $output);` 

B)をを使用してファイルに読まを線の配列に分割し、preg_grep()を使用して一致する行を探します。

$dat = file_get_contents('file.txt'); 
$lines = explode($dat, "\n"); 
$matches = preg_grep('/your pattern here/', $lines); 

c)行サイズの塊でファイルを読み取り、実行中の行数を保持して、各行でパターンを一致させます。

$fh = fopen('file.txt', 'rb'); 
$line = 1; 
while ($line = fgets($fh)) { 
    if (preg_match('/your pattern here/', $line)) { 
     ... whatever you need to do with matching lines ... 
    } 
    $line++; 
} 

それぞれは、その浮き沈み

a)はあなたが外部プログラムを起動していて、あなたのパターンは、任意のユーザーが入力したデータが含まれている場合、あなたが潜在的のシェルと同等に自分自身を開放していていますSQLインジェクション攻撃プラス面では、ファイル全体をスラップする必要はなく、メモリのオーバーヘッドを少しでも節約できます。

b)シェルインジェクション攻撃では安全ですが、ファイル全体をスラッシングする必要があります。ファイルが大きい場合は、おそらく使用可能なメモリを使い果たします。

c)大量の行を処理する場合は、すべての行を正規表現で呼び出すため、かなりのオーバーヘッドが発生します。

+0

私はあなたが私の質問のこの部分を逃したと思います:私は配列としてファイルを読み込んで、各行の正規表現を実行することができますが、問題は私の正規表現が結果をキャリッジリターン(改行)で一致させることです。 – bart

0

preg_match_allを使用して、すべての改行のオフセットを見つけ、既存のオフセットと比較することができます。

// read file to buffer 
$data = file_get_contents($datafile); 

// find all linefeeds in buffer  
$reg = preg_match_all("/\n/", $data, $lfall, PREG_OFFSET_CAPTURE); 
$lfs = $lfall[0]; 

// create an array of every offset 
$linenum = 1; 
$offset = 0;  
foreach($lfs as $lfrow) 
{ 
    $lfoffset = intval($lfrow[1]); 
    for(; $offset <= $lfoffset; $offset++) 
     $offsets[$offset] = $linenum; // offset => linenum 
    $linenum++; 
} 
0

これは動作しますが、非常に高価になる可能性があるすべての行で新しいpreg_match_allを実行します。ヨーヨーは、行番号を得れば

$file = file.txt; 

$log = array(); 

$line = 0; 

$pattern = '/\x20{2,}/'; 

if(is_readable($file)){ 

    $handle = fopen($file, 'rb'); 

    if ($handle) { 

     while (($subject = fgets($handle)) !== false) { 

      $line++; 

      if(preg_match_all ($pattern, $subject, $matches)){ 

       $log[] = array(
        'str' => $subject, 
        'file' => realpath($file), 
        'line' => $line, 
        'matches' => $matches, 
       ); 
      } 
     } 
     if (!feof($handle)) { 
      echo "Error: unexpected fgets() fail\n"; 
     } 
     fclose($handle); 
    } 
} 

別の方法としては、ファイルを読むことができ、その後、ファイル全体にpreg_match_allを行い、一致オフセットをcatpure。

$file = 'file.txt'; 
$length = 0; 
$pattern = '/\x20{2,}/'; 
$lines = array(0); 

if(is_readable($file)){ 

    $handle = fopen($file, 'rb'); 

    if ($handle) { 

     $subject = ""; 

     while (($line = fgets($handle)) !== false) { 

      $subject .= $line; 
      $lines[] = strlen($subject); 
     } 
     if (!feof($handle)) { 
      echo "Error: unexpected fgets() fail\n"; 
     } 
     fclose($handle); 

     if($subject && preg_match_all ($pattern, $subject, $matches, PREG_OFFSET_CAPTURE)){ 

      reset($lines); 

      foreach ($matches[0] as $key => $value) { 

       while(list($line, $length) = each($lines)){ // continues where we left off 

        if($value[1] < $length){ 

         echo "match is on line: " . $line; 

         break; //break out of while loop; 
        } 
       } 
      } 
     } 
    } 
}} 
0
//Keep it simple, stupid 

$allcodeline = explode(PHP_EOL, $content); 

foreach ($allcodeline as $line => $val) : 
    if (preg_match("#SOMEREGEX#i",$val,$res)) { 
     echo $res[0] . '!' . $line . "\n"; 
    } 
endforeach; 
+0

私はあなたが私の質問のこの部分を逃したと思います:私は配列としてファイルを読み込んで、各行の正規表現を実行することができますが、問題は私の正規表現が結果をキャリッジリターン(改行)で一致させることです。 – bart

1
$data = "Abba 
Beegees 
Beatles"; 

preg_match_all('/Abba|Beegees|Beatles/', $data, $matches, PREG_OFFSET_CAPTURE); 
foreach (current($matches) as $match) { 
    $matchValue = $match[0]; 
    $lineNumber = substr_count(mb_substr($data, 0, $match[1]), PHP_EOL) + 1; 

    echo "`{$matchValue}` at line {$lineNumber}\n"; 
} 

出力

`Abba` at line 1 
`Beegees` at line 2 
`Beatles` at line 3 

(パフォーマンス要件を確認してください)

関連する問題