2010-02-01 8 views
7

¿Hay alguna manera de usar regex para reemplazar caracteres en una cadena en función de la posición?Reemplazo basado en la posición en la cadena

Por ejemplo, una de mis reglas de reescritura para un proyecto que estoy trabajando es “reemplazar o con ö si o es la siguiente a la última vocal e impares (contando de izquierda a derecha).”

así, por ejemplo:

  • heabatoik se convertiría en heabatöik (o es la siguiente a la última vocal, así como el cuarto vocal)
  • habatoik no cambiaría (o es la siguiente a la última vocal, pero es la tercera vocal)

Es esto posible utilizando preg_replace en PHP?

Respuesta

8

Empezando por el principio de la cadena objetivo, que desea hacer coincidir 2 n + 1 vocales seguidas de un o, pero sólo si el o es seguido por exactamente una más vocal:

$str = preg_replace(
    '/^((?:(?:[^aeiou]*[aeiou]){2})*)' . # 2n vowels, n >= 0 
    '([^aeiou]*[aeiou][^aeiou]*)' .  # odd-numbered vowel 
    'o' .        # even-numbered vowel is o 
    '(?=[^aeiou]*[aeiou][^aeiou]*$)/', # exactly one more vowel 
    '$1$2ö', 
    'heaeafesebatoik'); 

Para hacer lo mismo pero para un partido o, con numeración impar 2 n principales vocales en lugar de 2 n + 1:

$str = preg_replace(
    '/^((?:(?:[^aeiou]*[aeiou]){2})*)' . # 2n vowels, n >= 0 
    '([^aeiou]*)' .      # followed by non-vowels 
    'o' .        # odd-numbered vowel is o 
    '(?=[^aeiou]*[aeiou][^aeiou]*$)/', # exactly one more vowel 
    '$1$2ö', 
    'habatoik'); 

Si no coincide, no realiza ningún reemplazo, por lo que es seguro ejecutarlos en secuencia si eso es lo que estás tratando de hacer.

+1

¿Por qué un '+ 'en ese último' [^ aeiou] + ' y no un '*'? –

+0

@Bart ¡Buena captura! –

+0

¡Supuse que * I * había mirado algo! :) –

1

Puede usar preg_match_all para dividir la cadena en partes vocales/no vocales y procesar eso.

p. Ej. algo así como

preg_match_all("/(([aeiou])|([^aeiou]+)*/", 
    $in, 
    $out, PREG_PATTERN_ORDER); 

Dependiendo de sus necesidades específicas, es posible que tenga que modificar la colocación de ()*+? en la expresión regular.

1

Me gusta expandirme en Schmitt. (No tengo suficientes puntos para agregar un comentario, no estoy tratando de robar su trueno). Usaría la bandera PREG_OFFSET_CAPTURE ya que devuelve no solo las vocales sino también las ubicaciones. Esta es mi solución:

const LETTER = 1; 
const LOCATION = 2 
$string = 'heabatoik' 

preg_match_all('/[aeiou]/', $string, $in, $out, PREG_OFFSET_CAPTURE); 

$lastElement = count($out) - 1; // -1 for last element index based 0 

//if second last letter location is even 
//and second last letter is beside last letter 
if ($out[$lastElement - 1][LOCATION] % 2 == 0 && 
    $out[$lastElement - 1][LOCATION] + 1 == $out[$lastElement][LOCATION]) 
     substr_replace($string, 'ö', $out[$lastElement - 1][LOCATION]); 

nota:

print_r(preg_match_all('/[aeiou]/', 'heabatoik', $in, $out, PREG_OFFSET_CAPTURE)); 
Array 
(
    [0] => Array 
     (
      [0] => Array 
       (
        [0] => e 
        [1] => 1 
       ) 

      [1] => Array 
       (
        [0] => a 
        [1] => 2 
       ) 

      [2] => Array 
       (
        [0] => a 
        [1] => 4 
       ) 

      [3] => Array 
       (
        [0] => o 
        [1] => 6 
       ) 

      [4] => Array 
       (
        [0] => i 
        [1] => 7 
       ) 
     ) 
) 
0

Ésta es la forma en que lo haría:

$str = 'heabatoik'; 

$vowels = preg_replace('#[^aeiou]+#i', '', $str); 
$length = strlen($vowels); 
if ($length % 2 && $vowels[$length - 2] == 'o') { 
    $str = preg_replace('#o([^o]+)$#', 'ö$1', $str); 
} 
Cuestiones relacionadas