2011-01-19 16 views
11

Estoy usando PHP preg_match_all() para buscar una cadena importada utilizando file_get_contents(). La expresión regular devuelve coincidencias pero me gustaría saber en qué número de línea se encuentran esas coincidencias. ¿Cuál es la mejor técnica para lograr esto?Obtener el número de línea de preg_match_all()

Pude leer el archivo como una matriz y realizar la expresión regular para cada línea, pero el problema es que mi expresión regular coincide con los resultados en los retornos de carro (líneas nuevas).

+1

voy a tirar una conjetura y decir que es posible que no pueda usa 'preg_match_all' para esto. – drudge

+0

preg_split y contar líneas en los resultados? Eso suena tonto ahora que lo dije. – scragz

+0

No veo ninguna manera fácil de lograr lo que quieres hacer ... –

Respuesta

8

bien, es un poco tarde, tal vez alrady resolvió esto, pero tuve que hacerlo y es bastante simple. usando PREG_OFFSET_CAPTURE bandera en preg_match devolverá la posición del carácter de la coincidencia. supongamos $ charpos, por lo

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

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

voilá!

10

No puede hacer esto solo con expresiones regulares. Al menos no limpiamente ¿Qué puede hacer para usar el indicador PREG_OFFSET_CAPTURE de preg_match_all y hacer un análisis posterior del archivo completo?

quiero decir después de tener el conjunto de cadenas que los partidos y las compensaciones a partir de cada cuerda simplemente contar cuántas \r\n o \n o \r son entre el principio del archivo y el desplazamiento para cada partido. El número de línea de la coincidencia sería el número de terminadores EOL distintos (\r\n | \n | \r) más 1.

1

creo que en primer lugar, es necesario leer los $ cadena en una matriz, se destacan cada elemento de cada línea, y se parecen a esto:

$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

Creo que te perdiste esta parte de mi pregunta: podría leer el archivo como una matriz y realizar la expresión regular para cada línea, pero el problema es que mi expresión regular coincide con los resultados en los retornos de carro (líneas nuevas). – bart

2

Tienes un par de opciones, pero ninguno son "simple":

a) exec() y utilizar el comando del sistema grep, que pueden reportar los números de línea:

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

b) sorber en el archivo usando file_get_contents(), divídalo en una matriz de líneas, luego use preg_grep() para encontrar las líneas correspondientes.

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

c) Leer el archivo en trozos de tamaño de línea, mantener un recuento línea en funcionamiento, y hacer su ajuste de patrones en cada línea.

$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++; 
} 

Cada uno tiene sus altibajos

una) Usted está invocando un programa externo, y si su patrón contiene los datos suministrados por el usuario, que está potencialmente abrirse a la cáscara equivalente de un ataque de inyección SQL. En el lado positivo, no tienes que sorber todo el archivo y ahorrarás un poco en la sobrecarga de memoria.

b) Estás a salvo de los ataques de inyección de la cáscara, pero tienes que sorber todo el archivo. Si su archivo es grande, probablemente agote la memoria disponible.

c) Está invocando una expresión regular en cada línea, lo que tendría una sobrecarga considerable si se trata de una gran cantidad de líneas.

+0

Creo que te perdiste esta parte de mi pregunta: podría leer el archivo como una matriz y realizar la expresión regular para cada línea, pero el problema es que mi expresión regular coincide con los resultados en los retornos de carro (líneas nuevas). – bart

0

Puede usar preg_match_all para encontrar las compensaciones de cada avance de línea y luego compararlas con las compensaciones que ya tiene.

// 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

Esto funciona pero realiza un nuevo preg_match_all en cada línea que podría ser bastante costoso.

$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); 
    } 
} 

Alternativamente se puede leer el archivo una vez yo obtener los números de línea y luego realizar la preg_match_all sobre el archivo completo y catpure las compensaciones de los partidos.

$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

Creo que te perdiste esta parte de mi pregunta: podría leer el archivo como una matriz y realizar la expresión regular para cada línea, pero el problema es que mi expresión regular coincide con los resultados en los retornos de carro (líneas nuevas). – 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"; 
} 

salida

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

(consultar los requisitos de rendimiento)

Cuestiones relacionadas