El problema está cuando marcamos como opcional la presencia de la llave de cierre: no tenemos en cuenta el caso de que detrás de la 'única letra' puede haber otra cosa distinta de espacios más llave de cierre (otras letras).
Entonces, se puede separar el problema en dos: tratarlo cuando hay llaves y cuando no.
Esta es una forma de hacerlo:
Using perl Syntax Highlighting
#!/usr/bin/env perl
use feature 'say';
#my $texto = q(\'{ A } \'A \=\i \`u \^e \^{e} \={\i} \'\i );
my $texto = q(Quiero capturar \'{ A }bcde junto a \'Abcd o \=\ibcd, pero no \'{Aa});
say "[$texto]";
my $unicaletra = qr/(?<unicaletra>(?:\\)?[aeiouAEOU])/;
$texto =~ s
/
(\\['´`=^~.]) # preámbulo
(?: # agrupación de opciones
\{ \s* $unicaletra \s* \} # primera opción, con llaves
|
$unicaletra # segunda opción, sin llaves
)
/$1\{$+{unicaletra}\}/gx;
say "[$texto]";
#say q([\'{A} \'{A} \={\i} \`{u} \^{e} \^{e} \={\i} \'{\i} ]);
say q([Quiero capturar \'{A}bcde junto a \'{A}bcd o \={\i}bcd, pero no \'{Aa}]);
__END__
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
La solución consiste en poner las dos opciones, usando el operador de alternancia de patrones '|'.
Otra forma de hacerlo es viendo si realmente existe una llave de apertura, y en ese caso, obligar a que exista una llave de cierre:
Using perl Syntax Highlighting
#!/usr/bin/env perl
use feature 'say';
#my $texto = q(\'{ A } \'A \=\i \`u \^e \^{e} \={\i} \'\i );
my $texto = q(Quiero capturar \'{ A }bcde junto a \'Abcd o \=\ibcd, pero no \'{Aa});
say "[$texto]";
$texto =~ s
/
(\\['´`=^~.]) # preámbulo
(?<llave> \{ \s*)? # caso de existir llave de apertura
(?<unicaletra>(?:\\)?[aeiouAEOU]) # la letra única
(?(<llave>) \s* \}) # si existe llave de apertura, debe existir llave de cierre
/$1\{$+{unicaletra}\}/gx;
say "[$texto]";
#say q([\'{A} \'{A} \={\i} \`{u} \^{e} \^{e} \={\i} \'{\i} ]);
say q([Quiero capturar \'{A}bcde junto a \'{A}bcd o \={\i}bcd, pero no \'{Aa}]);
__END__
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
En este caso usamos una expresión regular extendida, la
(?(condición)patrón si sí), que nos crea un subpatrón con la llave de cierre si existió la captura de la llave de apertura.
También hay que destacar el uso de grupos de captura con nombre (
<unicaletra>). De esa manera, en la expresión de sustitución no tenemos que andar calculando si la letra estaba en el segundo o tercer grupo de captura (podría ser cualquiera de los dos ya que hemos marcado el grupo de captura de la llave de apertura como opcional).
He usado también la opción
/x para poder desplegar el patrón por varias líneas y así poder comentarlas. La forma compacta sería así:
Using perl Syntax Highlighting
$texto =~ s/(\\['´`=^~.])(?<llave>\{\s*)?(?<unicaletra>(?:\\)?[aeiouAEOU])(?(<llave>)\s*\})/$1\{$+{unicaletra}\}/g;
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4