ayuda con programa java
Hola! alguien podria decirme como puedo eliminar el texto que esta dentro de /* comentarios */ e imprimir el resto del texto
Por ejemplo asi debe quedar:
Ingresa tu texto:
hola a todos /* necesito de su ayuda para */ poder programar
Tu texto sin comentarios queda asi:
hola a todos poder programar
BUILD SUCCESSFUL (total time: 6 seconds)
ya intente varias cosas pero no me queda, espero puedan ayudarme gracias
- Inicie sesión o regístrese para enviar comentarios
o.o?
Creo que hacerlo es mas fácil que explicarlo, de todas maneras si no entiendes la lógica del código me dices y te explico.
String salida = ""; // guardo caracter por caracter lo que no sea comentario
String[] comentarizado = new String[]{"/*","*/"};
/*
comentarizado[0] = caracteres de inicio de comentarios
comentarizado[1] = caracteres de fin comentario
*/
int index = 0; /* Es 0 si el caracter no es parte de un comentario y es 1 si lo es. */
for(int count = 0; count < mensaje.length(); count++){
if(count+comentarizado[index].length()<mensaje.length()){ /*esto es para evitar errores*/
String subMensaje = mensaje.substring(count,
count+comentarizado[index].length());
if(subMensaje.equals(comentarizado[index])){
if(index==0){
index = 1;
}else{
count+=comentarizado[index].length();
index = 0;
}
}
}
if(index==0){
salida+=mensaje.charAt(count);
}
}
return salida;
}
Ten en cuenta que este código no funciona muy bien si no se finaliza el comentarizado, ya que no valida el que se finalice, para hacerlo solo añades un IF, suerte.
PD: esta genial lo del blockcode :O
¿Puedes usar expresiones regulares?
Utiliza la siguiente expresión regular (
(?s)/\*((?!\*/).)*\*/
):public static void main (String[] args) throws java.lang.Exception {
String str = "hola a todos /* necesito de su ayuda para */ poder programar";
System.out.println(str.replaceAll("(?s)/\\*((?!\\*/).)*\\*/", ""));
}
}
Ver demo en línea.
Explicación de la expresión regular:
Visualización de la expresión regular:
Aquí hay un excelente tutorial sobre expresiones regulares (en inglés).
~~~
Inicialmente pensé que iba a
Inicialmente pensé que iba a hacer esto muy fácilmente pero me tomó mucho más tiempo del que creí.
Este programa itera una sola vez la entrada y va cambiando de estado dependiendo de donde este al recorrerla y toma acciones:
enum State {
INIT, NORMAL, COMMENT_START, COMMENT_END
}
public static void main( String ... args ) {
test("/* comment */", is(""));
test("/* comment */ text /* some test", is(" text /* some test"));
test("/* comment */ text */ some test", is(" text */ some test"));
test("/* comment */ test /* some */ text", is(" test text"));
test(" comment */ test /* some */ text", is(" comment */ test text"));
}
private static String removeComments( String input ) {
StringBuilder cb = new StringBuilder();
StringBuilder nb = new StringBuilder();
StringBuilder sb = nb;
char p = 'x';
int l = input.length();
State s = State.INIT;
for ( int i = 0 ; i < l; i++ ) {
char c = input.charAt(i);
if ( p == '/' && c == '*') s = State.COMMENT_START;
if ( p == '*' && c == '/'
&& s == State.COMMENT_START) s = State.COMMENT_END;
sb.append(p);
switch ( s ) {
case INIT:
s = State.NORMAL;
sb.deleteCharAt(i);
break;
case COMMENT_START:
sb.deleteCharAt(sb.length()-1);
sb = cb;
sb.append(p);
case NORMAL:
if ( i == l - 1 ) sb.append(c);
break;
case COMMENT_END:
s = State.NORMAL;
if ( i + 1 < l ) c = input.charAt(++i);
if (cb.length() > 0) cb.delete(0,cb.length());
sb = nb;
break;
}
p = c;
}
if ( sb == cb ) {
nb.append(cb);
sb = nb;
}
return sb.toString();
}
private static void test( String input, String expected ) {
String result;
assert (result = removeComments(input)).equals(expected):
String.format("got: [%s] expected: [%s]", result, expected);
}
private static String is(String s ) {return s;}
}
Definitivamente la version con regexp es la que usaría yo a menos que tuviera que procesar una cadena enorme.
Supongo que tengo que practicar más
RE: Inicialmente pensé que iba a
¿Seguro que tus test cases validan comentarios? Casi creo que te fuiste por la ruta de validar si un comentario está balanceado y si no lo está muestras el texto (lo qué según yo no hace, por ejemplo el compilador de Java).
En mi caso voy aquí:
val commentStart = st.indexOf("/*")
if(commentStart == -1){
st
}else{
val sub = st.substring(0, commentStart)
val subAfter = st.substring(commentStart);
val commentEnd = subAfter.indexOf("*/")
if(commentEnd == -1){
"Error: A comment should be balanced"
}else{
val subEnd = subAfter.substring(commentEnd + 2)
val newString = sub + subEnd;
replaceComment(newString)
}
}
}
/*Tests*/
replaceComment("/* comment */");
replaceComment("/* comment */ text /* some test"); // result => "Error: A comment should be balanced"
replaceComment("/* comment */ text */ some test");
replaceComment("/* comment */ test /* some */ text");
replaceComment(" comment */ test /* some */ text");
En este caso paso todos tus tests excepto el segundo... En dónde estoy viendo si le pongo algo que diga cómo que el comentario está sin balancear (para que se vea más compiler-like :p).
EDIT: Aquí dejo la versión Java.
public static void main(String ... args){
replaceComment("/* comment */");
replaceComment("/* comment */ text /* some test");
replaceComment("/* comment */ text */ some test");
replaceComment("/* comment */ test /* some */ text");
replaceComment(" comment */ test /* some */ text");
}
static void replaceComment(String st){
int commentStart = st.indexOf("/*");
while(commentStart != -1){
String startString = st.substring(0, commentStart);
String endString = st.substring(commentStart);
int commentEnd = endString.indexOf("*/");
if(commentEnd == -1){
st = "Error: Unbalanced comment";
}else{
String afterComment = endString.substring(commentEnd + 2);
st = new StringBuilder(startString).append(afterComment).toString();
}
commentStart = st.indexOf("/*");
}
System.out.println(new StringBuilder("Result is => ").append(st));
}
}
Si, porque no es un
Si, porque no es un comentario, sino un simple /* ( o */ ) En el caso de un lenguaje de programación el tratamiento es distinto porque quieres sacar instrucciones validas, si un comentario no termina todas las instrucciones después de que se abrió el comentario son invalidas.
De hecho si, mucho de la complicación que tuve fue para saber que hacer con lo que parecia un comentario que al final no lo fue. De nuevo la expresion regular funciona muy bien en este caso.
Re: Si, porque no es un
Refactorizando...
Quedaría:
public static void main(String ... args){
replaceComment("/* comment */");
replaceComment("/* comment */ text /* some test");
replaceComment("/* comment */ text */ some test");
replaceComment("/* comment */ test /* some */ text");
replaceComment(" comment */ test /* some */ text");
}
static void replaceComment(String st){
int commentStart = st.indexOf("/*");
while(commentStart != -1){
String startString = st.substring(0, commentStart);
String endString = st.substring(commentStart);
int commentEnd = endString.indexOf("*/");
if(commentEnd == -1)break;
String afterComment = endString.substring(commentEnd + 2);
st = new StringBuilder(startString).append(afterComment).toString();
commentStart = st.indexOf("/*");
}
System.out.println(new StringBuilder("Result is => ").append(st));
}
}
Ah, si mucho mejor y bastante
Ah, si mucho mejor y bastante simple. Creo que se puede mejorar aún más si en vez de crear un nuevo string cada vez usas un solo stringbuilder, pero eso haría más complejo el código para obtener substring / indexof etc.
Se ve bien.
Re: Ah, si mucho mejor y bastante
¡Gracias! (:
En este caso me dejé llevar por la onda esa de que la optimización prematura es la madre de todos los males. Aunque creo que si ayudaría cómo por un buen para el performance eso que sugieres.
Estaría excelente comparar la versión regex, con esta y con la StringBuilder en vez de crear una cadena. Aunque debo ser honesto, hacer esto me pareció un tanto "hereje", estoy muy metido en hacer programación y pensar de manera inmutable (por eso en el primer snippet uso recursividad, trato de que sea tail-recursive). Pero, estoy consiente que para este tipo de cosas programar inmutable es cómo usar un martillo para talar un árbol :p
Deja veo cómo quedaría con el builder para ver si te entendí.
En términos de legibilidad la
En términos de legibilidad la version de regex es más clara ( aunque parezca paradójico ) luego tu versión y luego la mía.
En términos de desempeño creo que los tres tendrían un comportamiento mucho muy similar incluso con entradas muy grandes. La razón por la cual yo lo hice de otra manera ( también pensé intuitivamente en usar substring index of y etc ) es porque quería ver si lo podia hacer con un solo loop (pensando erroneamente que indexOf internamente conlleva otro loop, pero en tu implementación funciona perfectamente.
El otro ejercicio sería hacer tu versión ( la correcta ) pero recursiva, de hecho tu loop es lo que hace precisamente: