2009-12-16 4 views
0

Ok ... J'ai une solution insatisfaisante à un problème.Remplacer des nombres variables d'éléments ... regex?

Le problème est que j'ai entrée comme ceci:

{sup 19}F({sup 3}He,t){sup 19}Ne(p){sup 18}F 

et besoin d'une sortie comme ceci:

¹⁹F(³He,t)¹⁹Ne(p)¹⁸F 

J'utilise une série de remplacements premier à diviser chacune des sections {sup xx} dans {supx} {sup x}, puis utilisez une regex pour faire correspondre chacun d'entre eux et remplacer les caractères par leurs équivalents uniques UTF-8. Le "problème" est que les {sup} sections peuvent avoir des nombres de 1, 2 ou 3 chiffres (peut-être plus, je ne sais pas), et je veux les "développer" en sections {sup} séparées avec un chiffre chacune . (J'ai aussi le même problème avec {sub} pour ... indices)

Ma solution actuelle ressemble à ceci (en java):

retval = retval.replaceAll("\\{sup ([1-9])([0-9])\\}", "{sup $1}{sup $2}"); 
retval = retval.replaceAll("\\{sup ([1-9])([0-9])([0-9])\\}", "{sup $1}{sup $2}{sup $3}"); 

Ma question: est-il possible de le faire en un seul passage, peu importe combien de chiffres (ou au moins un nombre raisonnable) il y a?

Répondre

3

Oui, mais cela peut être un peu un hack, et vous devrez faire attention il ne overmatch!

Regex:

(?:\{sup\s)?(\d)(?=\d*})}? 

chaîne de remplacement:

{sup $1} 

Une brève explication:

(?:       | start non-capturing group 1 
    \{       | match the character '{' 
    sup       | match the substring: "sup" 
    \s       | match any white space character 
)        | end non-capturing group 1 
?        | ...and repeat it once or not at all 
(        | start group 1 
    \d       | match any character in the range 0..9 
)        | end group 1 
(?=       | start positive look ahead 
    \d       | match any character in the range 0..9 
    *       | ...and repeat it zero or more times 
    }       | match the substring: "}" 
)        | stop negative look ahead 
}        | match the substring: "}" 
?        | ...and repeat it once or not at all 

En clair: il correspond à un seul chiffre, que quand on regarde en avant il y a } avec des chiffres optionnels entre les deux. Si possible, les sous-chaînes {sup et } sont également remplacées.

EDIT:

Une meilleure est la suivante:

(?:\{sup\s|\G)(\d)(?=\d*})}? 

De cette façon, les chiffres comme dans la chaîne "set={123}" ne seront pas remplacés. Le \G dans ma deuxième regex correspond à l'endroit où le match précédent s'est terminé.

+0

Pourquoi avez-vous marqué la partie '{sup' comme optionnelle? On dirait qu'il va correspondre "1}". –

+0

@Mike: l'OP veut remplacer '{sup 123}' par '{sup 1} {sup 2} {sup 3}'. Seul le premier chiffre a '{sup' devant et le dernier chiffre a '}' après: c'est pourquoi c'est facultatif. –

+0

@Mike: ah, je vois ce que tu veux dire. D'où ma remarque "il faut faire attention, ça ne * surpasse pas!". Voyez ma deuxième solution, celle qui contient le '\ G ', ce qui explique cela. –

0

Bien sûr, il s'agit d'une construction d'expression régulière standard. Vous pouvez trouver tous les méta-caractères dans le Pattern Javadoc, mais pour vos besoins, vous voulez probablement le méta-caractère "+", ou le quantificateur gourmand {1,3}. Détails dans le lien.

+0

Non, vous avez mal compris, l'OP ne cherche pas à faire correspondre un ou plusieurs chiffres. –

1

La manière la plus simple de faire ce genre de chose est avec quelque chose comme les délégués preg_replace_callback de PHP ou MatchEvaluator de .NET. Java n'a rien de tel que celui intégré, mais il expose l'API de niveau inférieur qui vous permet de l'implémenter vous-même.Voici une façon de le faire:

import java.util.regex.*; 

public class Test 
{ 
    static String sepsup(String orig) 
    { 
    Pattern p = Pattern.compile("(\\{su[bp])(\\d+)\\}"); 
    Matcher m = p.matcher(orig); 
    StringBuffer sb = new StringBuffer(); 
    while (m.find()) 
    { 
     m.appendReplacement(sb, ""); 
     for (char ch : m.group(2).toCharArray()) 
     { 
     sb.append(m.group(1)).append(ch).append("}"); 
     } 
    } 
    m.appendTail(sb); 
    return sb.toString(); 
    } 

    public static void main (String[] args) 
    { 
    String s = "{sup 19}F({sup 3}He,t){sub 19}Ne(p){sup 18}F"; 
    System.out.println(s); 
    System.out.println(sepsup(s)); 
    } 
} 

Résultat:

{sup 19}F({sup 3}He,t){sub 19}Ne(p){sup 18}F 
{sup 1}{sup 9}F({sup 3}He,t){sub 1}{sub 9}Ne(p){sup 1}{sup 8}F 

Si vous voulez, vous pouvez aller de l'avant et de générer les caractères et superscript et insérez ceux en indice à la place.