Perhaps you want to find the positions of all anchor tags. This will return a two dimensional array of which the starting and ending positions will be returned.
<?php
function getTagPositions($strBody)
{
define(DEBUG, false);
define(DEBUG_FILE_PREFIX, "/tmp/findlinks_");
preg_match_all("/<[^>]+>(.*)<\/[^>]+>/U", $strBody, $strTag, PREG_PATTERN_ORDER);
$intOffset = 0;
$intIndex = 0;
$intTagPositions = array();
foreach($strTag[0] as $strFullTag) {
if(DEBUG == true) {
$fhDebug = fopen(DEBUG_FILE_PREFIX.time(), "a");
fwrite($fhDebug, $fulltag."\n");
fwrite($fhDebug, "Starting position: ".strpos($strBody, $strFullTag, $intOffset)."\n");
fwrite($fhDebug, "Ending position: ".(strpos($strBody, $strFullTag, $intOffset) + strlen($strFullTag))."\n");
fwrite($fhDebug, "Length: ".strlen($strFullTag)."\n\n");
fclose($fhDebug);
}
$intTagPositions[$intIndex] = array('start' => (strpos($strBody, $strFullTag, $intOffset)), 'end' => (strpos($strBody, $strFullTag, $intOffset) + strlen($strFullTag)));
$intOffset += strlen($strFullTag);
$intIndex++;
}
return $intTagPositions;
}
$strBody = 'I have lots of <a href="http://my.site.com">links</a> on this <a href="http://my.site.com">page</a> that I want to <a href="http://my.site.com">find</a> the positions.';
$strBody = strip_tags(html_entity_decode($strBody), '<a>');
$intTagPositions = getTagPositions($strBody);
print_r($intTagPositions);
/*****
Output:
Array (
[0] => Array (
[start] => 15
[end] => 53 )
[1] => Array (
[start] => 62
[end] => 99 )
[2] => Array (
[start] => 115
[end] => 152 )
)
*****/
?>
preg_match_all
(PHP 4, PHP 5)
preg_match_all — Realizar una comparación global con una expresión regular
Descripción
Busca el asunto por todas las coincidencias con la expresión regular dada en patron , y las coloca en coincidencias en el orden especificado por banderas .
Después de que la primera coincidencia es encontrada, las búsquedas subsiguientes continúan desde el final de la última coincidencia.
Lista de parámetros
- patron
-
El patrón a buscar, como una cadena.
- asunto
-
La cadena de entrada.
- coincidencias
-
Una matriz multi-dimensional con todas las coincidencias ordenadas de acuerdo al parámetro banderas .
- banderas
-
Puede ser una combinación de las siguientes banderas (note que no tiene sentido usar PREG_PATTERN_ORDER junto con PREG_SET_ORDER):
- PREG_PATTERN_ORDER
-
Ordena los resultados de tal forma que $coincidencias[0] es una matriz con las coincidencias completas del patrón, $coincidencias[1] es una matriz con las cadenas que coinciden con el primer sub-patrón entre paréntesis, y así sucesivamente.
<?php
preg_match_all("|<[^>]+>(.*)</[^>]+>|U",
"<b>ejemplo: </b><div align=left>esta es una prueba</div>",
$salida, PREG_PATTERN_ORDER);
echo $salida[0][0] . ", " . $salida[0][1] . "\n";
echo $salida[1][0] . ", " . $salida[1][1] . "\n";
?>El resultado del ejemplo seria:
<b>ejemplo: </b>, <div align=left>esta es una prueba</div> ejemplo: , esta es una prueba
Así que $salida[0] contiene una matriz de cadenas que coincidieron con el patrón completo, y $salida[1] contiene una matriz de cadenas ubicadas entre etiquetas.
- PREG_SET_ORDER
-
Ordena los resultados de forma tal que $coincidencias[0] es una matriz que contiene el primer conjunto de coincidencias, $coincidencias[1] es una matriz con el segundo conjunto de coincidencias, y así sucesivamente.
<?php
preg_match_all("|<[^>]+>(.*)</[^>]+>|U",
"<b>ejemplo: </b><div align=\"left\">esta es una prueba</div>",
$salida, PREG_SET_ORDER);
echo $salida[0][0] . ", " . $salida[0][1] . "\n";
echo $salida[1][0] . ", " . $salida[1][1] . "\n";
?>El resultado del ejemplo seria:
<b>ejemplo: </b>, ejemplo: <div align="left">esta es una prueba</div>, esta es una prueba
- PREG_OFFSET_CAPTURE
-
Si es pasada esta bandera, para cada coincidencia que ocurre, será devuelto también el desplazamiento de la cadena adjunta. Note que esto modifica el valor de coincidencias , convirtiéndolo en una matriz en donde cada elemento es una matriz que consiste de la cadena que coincidió en la posición 0, y su desplazamiento de cadena al interior del asunto en la posición 1.
Si no se indica bandera alguna, se asume el uso de PREG_PATTERN_ORDER.
- desplazamiento
-
Normalmente, la búsqueda comienza desde el inicio de la cadena de asunto. El parámetro opcional desplazamiento puede ser usado para especificar el lugar alternativo desde donde debe iniciar la búsqueda (en bytes).
Note: El uso de desplazamiento no es equivalente a pasar substr($asunto, $desplazamiento) a preg_match_all() en lugar de la cadena de asunto, ya que patron puede contener aserciones como ^, $ o (?<=x). Vea preg_match() para más ejemplos.
Valores retornados
Devuelve el número de coincidencias con el patrón completo (que puede ser cero), o FALSE si ocurre un error.
Registro de cambios
| Versión | Descripción |
|---|---|
| 4.3.3 | Fue agregado el parámetro desplazamiento |
| 4.3.0 | Fue agregada la bandera PREG_OFFSET_CAPTURE |
Ejemplos
Example #1 Obtener todos los números telefónicos de un segmento de texto.
<?php
preg_match_all("/\(? (\d{3})? \)? (?(1) [\-\s] ) \d{3}-\d{4}/x",
"Llame al 555-1212 1-800-555-1212", $telefonos);
?>
Example #2 Encontrar etiquetas HTML coincidentes (de forma ambiciosa)
<?php
// El \\2 es un ejemplo de referencia hacia atrás. Este le dice a pcre
// que debe buscar el segundo conjunto de paréntesis en la expresión
// regular misma, que sería ([\w]+) en este caso. La barra invertida
// extra es requerida ya que la cadena se encuentra entre comillas
// dobles.
$html = "<b>texto en negrilla</b><a href=hola.html>haga clic aquí</a>";
preg_match_all("/(<([\w]+)[^>]*>)(.*)(<\/\\2>)/", $html, $coincidencias, PREG_SET_ORDER);
foreach ($coincidencias as $val) {
echo "coincidencia: " . $val[0] . "\n";
echo "parte 1: " . $val[1] . "\n";
echo "parte 2: " . $val[3] . "\n";
echo "parte 3: " . $val[4] . "\n\n";
}
?>
El resultado del ejemplo seria:
coincidencia: <b>texto en negrilla</b> parte 1: <b> parte 2: texto en negrilla parte 3: </b> coincidencia: <a href=hola.html>haga clic aquí</a> parte 1: <a href=hola.html> parte 2: haga clic aquí parte 3: </a>
preg_match_all
19-Jun-2008 01:46
04-Mar-2008 12:13
To count str_length in UTF-8 string i use
$count = preg_match_all("/[[:print:]\pL]/u", $str, $pockets);
where
[:print:] - printing characters, including space
\pL - UTF-8 Letter
/u - UTF-8 string
other unicode character properties on http://www.pcre.org/pcre.txt
28-Jan-2008 04:30
please note, that the function of "mail at SPAMBUSTER at milianw dot de" can result in invalid xhtml in some cases. think i used it in the right way but my result is sth like this:
<img src="./img.jpg" alt="nice picture" />foo foo foo foo </img>
correct me if i'm wrong.
i'll see when there's time to fix that. -.-
12-Jul-2007 02:57
<?php
// Returns an array of strings where the start and end are found
function findinside($start, $end, $string) {
preg_match_all('/' . preg_quote($start, '/') . '([^\.)]+)'. preg_quote($end, '/').'/i', $string, $m);
return $m[1];
}
$start = "mary has";
$end = "lambs.";
$string = "mary has 6 lambs. phil has 13 lambs. mary stole phil's lambs. now mary has all the lambs.";
$out = findinside($start, $end, $string);
print_r ($out);
/* Results in
(
[0] => 6
[1] => all the
)
*/
?>
26-Jun-2007 11:22
If you'd like to include DOUBLE QUOTES on a regular expression for use with preg_match_all, try ESCAPING THRICE, as in: \\\"
For example, the pattern:
'/<table>[\s\w\/<>=\\\"]*<\/table>/'
Should be able to match:
<table>
<row>
<col align="left" valign="top">a</col>
<col align="right" valign="bottom">b</col>
</row>
</table>
.. with all there is under those table tags.
I'm not really sure why this is so, but I tried just the double quote and one or even two escape characters and it won't work. In my frustration I added another one and then it's cool.
06-Dec-2006 06:20
This is a function to convert byte offsets into (UTF-8) character offsets (this is reagardless of whether you use /u modifier:
<?php
function mb_preg_match_all($ps_pattern, $ps_subject, &$pa_matches, $pn_flags = PREG_PATTERN_ORDER, $pn_offset = 0, $ps_encoding = NULL) {
// WARNING! - All this function does is to correct offsets, nothing else:
//
if (is_null($ps_encoding))
$ps_encoding = mb_internal_encoding();
$pn_offset = strlen(mb_substr($ps_subject, 0, $pn_offset, $ps_encoding));
$ret = preg_match_all($ps_pattern, $ps_subject, $pa_matches, $pn_flags, $pn_offset);
if ($ret && ($pn_flags & PREG_OFFSET_CAPTURE))
foreach($pa_matches as &$ha_match)
foreach($ha_match as &$ha_match)
$ha_match[1] = mb_strlen(substr($ps_subject, 0, $ha_match[1]), $ps_encoding);
//
// (code is independent of PREG_PATTER_ORDER / PREG_SET_ORDER)
return $ret;
}
?>
20-Feb-2006 12:53
Here's some fleecy code to 1. validate RCF2822 conformity of address lists and 2. to extract the address specification (the part commonly known as 'email'). I wouldn't suggest using it for input form email checking, but it might be just what you want for other email applications. I know it can be optimized further, but that part I'll leave up to you nutcrackers. The total length of the resulting Regex is about 30000 bytes. That because it accepts comments. You can remove that by setting $cfws to $fws and it shrinks to about 6000 bytes. Conformity checking is absolutely and strictly referring to RFC2822. Have fun and email me if you have any enhancements!
<?php
function mime_extract_rfc2822_address($string)
{
//rfc2822 token setup
$crlf = "(?:\r\n)";
$wsp = "[\t ]";
$text = "[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F]";
$quoted_pair = "(?:\\\\$text)";
$fws = "(?:(?:$wsp*$crlf)?$wsp+)";
$ctext = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F" .
"!-'*-[\\]-\\x7F]";
$comment = "(\\((?:$fws?(?:$ctext|$quoted_pair|(?1)))*" .
"$fws?\\))";
$cfws = "(?:(?:$fws?$comment)*(?:(?:$fws?$comment)|$fws))";
//$cfws = $fws; //an alternative to comments
$atext = "[!#-'*+\\-\\/0-9=?A-Z\\^-~]";
$atom = "(?:$cfws?$atext+$cfws?)";
$dot_atom_text = "(?:$atext+(?:\\.$atext+)*)";
$dot_atom = "(?:$cfws?$dot_atom_text$cfws?)";
$qtext = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F!#-[\\]-\\x7F]";
$qcontent = "(?:$qtext|$quoted_pair)";
$quoted_string = "(?:$cfws?\"(?:$fws?$qcontent)*$fws?\"$cfws?)";
$dtext = "[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F!-Z\\^-\\x7F]";
$dcontent = "(?:$dtext|$quoted_pair)";
$domain_literal = "(?:$cfws?\\[(?:$fws?$dcontent)*$fws?]$cfws?)";
$domain = "(?:$dot_atom|$domain_literal)";
$local_part = "(?:$dot_atom|$quoted_string)";
$addr_spec = "($local_part@$domain)";
$display_name = "(?:(?:$atom|$quoted_string)+)";
$angle_addr = "(?:$cfws?<$addr_spec>$cfws?)";
$name_addr = "(?:$display_name?$angle_addr)";
$mailbox = "(?:$name_addr|$addr_spec)";
$mailbox_list = "(?:(?:(?:(?<=:)|,)$mailbox)+)";
$group = "(?:$display_name:(?:$mailbox_list|$cfws)?;$cfws?)";
$address = "(?:$mailbox|$group)";
$address_list = "(?:(?:^|,)$address)+";
//output length of string (just so you see how f**king long it is)
echo(strlen($address_list) . " ");
//apply expression
preg_match_all("/^$address_list$/", $string, $array, PREG_SET_ORDER);
return $array;
};
?>
02-Feb-2006 10:05
PREG_OFFSET_CAPTURE always seems to provide byte offsets, rather than character position offsets, even when you are using the unicode /u modifier.
