2011-01-20 15 views
5

Estoy tratando de convertir una ecuación RPN en una cadena que coincida con las reglas de tigcc. Los números deben tener el número de caracteres frente a ellos y una etiqueta positiva o negativa. Por "2" que sería "1 2 POSINT_TAG"Uso de funciones o métodos en String.replaceAll() regex de Java

Mi entrada completa al convertidor RPN se basa en expresiones regulares, así que quería hacer uso de ellos y tienen un String.replaceAll() función como:

string.replaceAll("(\d+)","$1".length+" $1 POSINT_TAG"); 

Pero hay simplemente imprime: "2 números INT_TAG". Encontré algunas clases como com.stevesoft.pat (link).

¿Hay alguna otra forma de implementar Sun Java normal para usar las funciones (personalizadas) en reemplazar las reglas de expresiones regulares?

Respuesta

13

No, al menos no de la misma manera que lo haría en C# o Ruby.

Lo más parecido es escribir un bucle como este:

static Pattern pattern = Pattern.compile("\\d+"); 
String convert(String input) { 
    StringBuffer output = new StringBuffer(); 
    Matcher matcher = pattern.matcher(input); 
    while (matcher.find()) { 
     String rep = 
      String.format("%d %s POSINT_TAG", 
          matcher.group().length(), 
          matcher.group()); 
     matcher.appendReplacement(output, rep); 
    } 
    matcher.appendTail(output); 
    return output.toString(); 
} 
+3

FYI, aunque se prefiere generalmente StringBuilder, 'appendReplacement()' y 'appendTail()' no lo aceptan; tienes que usar StringBuffer en su lugar. (StringBuilder no existía aún cuando se agregó la clase Matcher, en JDK 1.4.) –

+0

+1 al comentario - Sigo esperando que añadan una sobrecarga de estos métodos que pueden tomar cualquier 'Appendable' pero (a partir de la actual Construcciones Java 8) todavía hay solo la versión 'StringBuffer'. –

+1

Puede que le divierta saber que [esta respuesta se cita en el código fuente de la aplicación móvil Stack Overflow para Android] (http://meta.stackexchange.com/a/277077/254929). – Air

1

Desafortunadamente lo que están tratando aquí no va a funcionar. Java usa evaluación de orden aplicativa, lo que significa que los argumentos se evalúan antes de que se llame a la función. En su caso, obtendrá la longitud de la cadena de dos caracteres "$1", no la cantidad de dígitos que se capturarán en el grupo n. ° 1.

Así que cuando se utiliza esta línea:

string.replaceAll("(\\d+)","$1".length+" $1 POSINT_TAG"); 

Lo que ve es la función:

string.replaceAll("(\\d+)","2 $1 POSINT_TAG"); 

En cuanto a una solución a su problema, la respuesta Publicado por finnw funcionará.

3

Tengo una idea sobre el reemplazo de cadenas personalizadas en Java. No es tan fácil como la función de reemplazo en JavaScript, pero funciona bien. Aquí está el código:


    package org.eve.util; 

    import java.lang.reflect.Method; 
    import java.lang.reflect.Modifier; 
    import java.util.regex.Matcher; 
    import java.util.regex.Pattern; 

    public class StringUtils{ 
     public static String replaceWithFn(CharSequence input,String regexp,Method fn,int group){ 
      Matcher m=Pattern.compile(regexp).matcher(input); 
      StringBuffer sb=new StringBuffer(); 
      try { 
       Object obj=Modifier.toString(fn.getModifiers()).indexOf("static")>-1? 
         fn.getClass():fn.getDeclaringClass().newInstance(); 
       if(fn.getReturnType()!=String.class){ 
        System.out.println("replacement function must return type \"String\"."); 
       } 
       while(m.find()){ 
        m.appendReplacement(sb, (String)fn.invoke(obj, m.group(group))); 
       } 
       m.appendTail(sb); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return sb.toString(); 
     } 
    } 

 

 
    package org.eve.test;

import org.eve.util.StringUtils; 

public class ReplaceTest { 
    public static void main(String[] args) { 
     try { 
      StringBuffer input=new StringBuffer("\\u039D\\u03B9\\u03BA\\u03CC\\u03BB\\u03B1\\u03BF\\u03C2 Nicholas \\u5C3C\\u53E4\\u62C9\\u65AF"); 
      System.out.println("input="+input); 
      String result=StringUtils.replaceWithFn(
       input, 
       "\\\\u([0-9a-zA-Z]{4})", 
       ReplaceTest.class.getMethod("hex2char",String.class), 
       1 
      ); 
      System.out.println("output="+result); 
     } catch (SecurityException e) { 
      e.printStackTrace(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } 
    } 

    public String hex2char(String s){ 
     //TODO replaceholder 
     return String.valueOf((char)Integer.parseInt(s,16)); 
    } 
} 

Sólo por diversión.

+0

¡Esto funciona perfectamente! Usé una interfaz en lugar de reflexión: https://github.com/redstone/LegacyFactions/blob/fcf1410e99cbe1e82fabcf84827b44e01af719a6/src/main/java/net/redstoneore/legacyfactions/util/StringUtils.java#L8 –

Cuestiones relacionadas