[Alg/Java] Snel tekst converteren naar tekst met escapes

Pagina: 1
Acties:
  • 119 views sinds 30-01-2008
  • Reageer

  • GigaTexel_BE
  • Registratie: April 2002
  • Laatst online: 15:46
Voor mijn thesis gebruik in de webots software (robot simulator)
De omgeving waarin de robot zich beweegt is via de GUI in te stellen, maar dit vergt zeer veel tijd en moeite.
Die omgeving wordt opgeslaan als een VRML file en is dus leesbaar/editeerbaar in elke mogelijk editor.

Het aantal experimenten is bekend en de parameters die moeten varieren ook.
Voorbeeld: de robot laten bewegen in een T-Maze met veranderlijke breedte van alle balken
pic (hier met een rat): http://www.ratbehavior.org/images/TMaze.jpg

Gezien deze genericiteit, wil ik een doodsimpel java applicatietje schrijven die de tekstfile (VRML) genereert en wegschrijft. Op zich geen probleem: ik neem gewoon de standaardfile, en schrijf die enkele keren uit met andere parameters.
Probleem ligt hem eigenlijk bij de leesbaarheid: de tabs en newlines zouden behouden moeten blijven, aangezien anders de boel niet meer leesbaar blijft

Concreet: ik zoek een oplossing om een voorbeeld van zo een omgevingsfile in de lezen en alle tabs en newlines omzet naar de gebruikelijke escape karakters zodat ik die gewoon kan wegschrijven in java

Even verduidelijken: het WorldInfo-veld uit de VRML is steeds dezelfde:
code:
1
2
3
4
5
6
7
WorldInfo {
  info [
    "Description"
    "Author: first name last name <e-mail>"
    "Date: DD MMM YYYY"
  ]
}


Wanneer ik dus in mijn javacode zo een header wil wegschrijven naar mijn bestand, maak ik een String object aan, dat nooit verandert:

Java:
1
final static String WorldInfo = new String("WorldInfo {\r\n  \tinfo [\r\n    \t\t\"Description\"\r\n    \t\t\"Author: first name last name <e-mail>\"\r\n    \t\t\"Date: DD MMM YYYY\"\r\n  \t]\r\n}\r\n");


Ik zoek dus een snelle oplossing om alle tags die nooit veranderen (die uit het eerste codefragment) om te zetten naar de tekst in de constructor van het Stringobject

Siesteem Spekkies!


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Even in char array zetten en vervolgens in een switch functie de chars in kwestie afvangen en wegschrijven als escapestrings?

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Je kan toch gewoon de string inlezen en dan iets van

myString = myString.Replace( "\r", "\\r" ).Replace( "\n", "\\n" ).Replace( "\t", "\\t" );

Het lijkt me dat er niet veel andere characters zijn die je moet escapen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Daar is de String#replaceAll() inderdaad geschikt voor. Maar dat lijkt me een duurdere operatie in geval van langere strings, het is immers regexp. Een char array char voor char uitlezen (van en naar een buffer uiteraard) is dan sneller.

  • GigaTexel_BE
  • Registratie: April 2002
  • Laatst online: 15:46
BalusC schreef op zaterdag 24 november 2007 @ 14:52:
Daar is de String#replaceAll() inderdaad geschikt voor. Maar dat lijkt me een duurdere operatie in geval van langere strings, het is immers regexp. Een char array char voor char uitlezen (van en naar een buffer uiteraard) is dan sneller.
de operatie moet maar 1 keer gebeuren, aangezien die boel toch hardcoded in de code gaat. Tis niet de bedoeling een wetenschappelijk verantwoord programma te schrijven, enkel een hulpmiddeltje in mijn onderzoek :)

hoedanook, de voorgestelde oplossing blijkt niet te werken:

Ik lees de hele boel in, in een StringBuffer:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
            StringBuffer temp = new StringBuffer("");
            
            BufferedReader bufRead = new BufferedReader(input);
            
            String line;    // String that holds current file line           
            
            // Read first line
            line = bufRead.readLine();
            
            while (line != null){
                temp.append(line);
                line = bufRead.readLine();
            }


en schrijf dan weg, met de voorgestelde oplossing:

Java:
1
2
3
4
            FileWriter fstream = new FileWriter("Tempfile.txt");
            BufferedWriter out = new BufferedWriter(fstream);
            
            out.write(temp.toString().replaceAll( "\r", "\\r" ).replaceAll( "\n", "\\n" ).replaceAll( "\t", "\\t" ));


(na het sluiten van de file enzow) staat er in Tempfile.txt:
code:
1
#VRML_SIM V5.0 utf8#000000#!mainWindow: -0.0046875 -0.00779221 1.............


ipv

code:
1
#VRML_SIM V5.0 utf8\r\n#000000\r\n#!mainWindow: -0.0046875 -0.00779221 1........

Siesteem Spekkies!


  • GigaTexel_BE
  • Registratie: April 2002
  • Laatst online: 15:46
net even geprobeerd met

Java:
1
out.write(temp.toString().replaceAll( "\\r", "\\\\r" ).replaceAll( "\\n", "\\\\n" ).replaceAll( "\\t", "\\\\t" ));


echter, zelfde resultaat

Siesteem Spekkies!


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Je moet "\r" vervangen, niet "\\r".

  • GigaTexel_BE
  • Registratie: April 2002
  • Laatst online: 15:46
dan zou de eerste toch moeten werken?

Siesteem Spekkies!


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

De "\" is een escapeteken binnen String. Wanneer je een enkele "\" wilt weergeven, dan zul je deze ook moeten escapen. Dus wanneer je "\\" wilt weergeven, escape je deze als "\\\\".

  • GigaTexel_BE
  • Registratie: April 2002
  • Laatst online: 15:46
dus wat zou volgens jou dan wel moeten werken?

Siesteem Spekkies!


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Het vervangen van de enkele karakter die wordt aangeven met "\r" door de letterlijke tekenreeks "\\r" en het laatste moet je uiteraard escapen.

  • flowerp
  • Registratie: September 2003
  • Laatst online: 11-09-2025
BalusC schreef op zondag 25 november 2007 @ 12:07:
Het vervangen van de enkele karakter die wordt aangeven met "\r" door de letterlijke tekenreeks "\\r" en het laatste moet je uiteraard escapen.
Inderdaad, in het geval van de TS dus:

Java:
1
out.write(temp.toString().replaceAll( "\r", "\\\\r" ).replaceAll( "\n", "\\\\n" ).replaceAll( "\t", "\\\\t" ));


Dit is overigens wel een bekend instinkertje. Als je op het eerste oog naar de replaceAll method kijkt lijkt het net of het 2de argument een gewone string replacement is, en dan zo \\r genoeg zijn. Echter $'s en \'s worden op een speciale manier geïnterpreteerd. Zie de Javadoc van Matcher.replaceAll:
* Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
* the replacement string may cause the results to be different than if it
* were being treated as a literal replacement string. Dollar signs may be
* treated as references to captured subsequences as described above, and
* backslashes are used to escape literal characters in the replacement
* string.
Als je b.v. iets als het volgende gebruikt heb je niet de dubbele escaping nodig:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public String escape(String input) {
        
        if ( input == null ) {
            return "";
        }
        
        StringBuilder escaped = new StringBuilder();
        
        for ( char c : input.toCharArray() ) {
            switch (c) {
                case '\r':
                    escaped.append("\\r");
                break;              
                    
                case '\t':
                    escaped.append("\\t");
                break;
                
                default:
                    escaped.append(c);          
            }
        }       
        return escaped.toString();
    }

[ Voor 0% gewijzigd door flowerp op 25-11-2007 17:54 . Reden: StringBuffer -> StringBuilder ]

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Voeg een case voor de \n toe en gebruik StringBuilder ipv StringBuffer, dan had ik die bijna precies in mijn gedachten tijdens de 1e reply van dit topic.

  • flowerp
  • Registratie: September 2003
  • Laatst online: 11-09-2025
BalusC schreef op zondag 25 november 2007 @ 17:37:
Voeg een case voor de \n toe en gebruik StringBuilder ipv StringBuffer, dan had ik die bijna precies in mijn gedachten tijdens de 1e reply van dit topic.
Ja, natuurlijk. 'Stomme' fout van mij. Even te snel ingetikt. Voor de mensen die niet weten waar 't over gaat: de StringBuffer is een legacy classe die je alleen gebruikt als het ding shared is tussen threads, maar zelfs dan nog synchroniseer je in de praktijk dikwijls op een andere niveau.

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


  • Swinnio
  • Registratie: Maart 2001
  • Laatst online: 15:00
flowerp schreef op zondag 25 november 2007 @ 17:54:
[...]


Ja, natuurlijk. 'Stomme' fout van mij. Even te snel ingetikt. Voor de mensen die niet weten waar 't over gaat: de StringBuffer is een legacy classe die je alleen gebruikt als het ding shared is tussen threads, maar zelfs dan nog synchroniseer je in de praktijk dikwijls op een andere niveau.
Tenzij TS om een of andere reden aan Java 1.4 vastzit natuurlijk, want StringBuilder bestaat pas vanaf 1.5. Overigens is het sowieso de vraag of het in de praktijk veel uitmaakt, aangezien het slechts eenmalig uitgevoerd wordt.

If the world wouldn't suck, we'd all fall off


  • flowerp
  • Registratie: September 2003
  • Laatst online: 11-09-2025
Swinnio schreef op dinsdag 27 november 2007 @ 15:29:
[...]
Tenzij TS om een of andere reden aan Java 1.4 vastzit natuurlijk, want StringBuilder bestaat pas vanaf 1.5.
Ah kom op joh ;) 1.5 is uit 2004! En 1.4 zelfs uit 2002. Ik weet dat er in het begin een beetje weerstand tegen 1.5 was, maar we zitten nu ruim 3 jaar verder en zelfs 1.6 is al uit.

Aangezien TS met z'n thesis bezig is neem ik aan dat hij gewoon de JDK van de website van Sun heeft gedownload, en dan krijg je alweer een jaar lang automatisch de 1.6 JVM.
Overigens is het sowieso de vraag of het in de praktijk veel uitmaakt, aangezien het slechts eenmalig uitgevoerd wordt.
Dat is inderdaad zo. Het is in veel gevallen een micro-optimalisatie. Als je in de gemiddelde app al je StringBuffers door StringBuilders gaat vervangen voorspel ik dat je er inderdaad waarschijnlijk weinig van merkt. Toch is het netter als je voor nieuwe code gewoon default de StringBuilder gebruikt, zeker als het om example code gaat. Er zitten ook voorderest geen enkele nadelen aan StringBuilder ofzo, dus gewoon standaard gebruiken :)

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Sorry hoor, ik ben de laatste tijd niet meer echt van de Java, maar het gaat hier om een simpel begrip.

De ts heeft in zijn source string een Regel einde staan (/n of /r/n) en wil deze escapen zodat het op een regel past. Je zult dus /r en /n moeten escapen naar //r en //n. In welke taal of welke methodes je ervoor gebruik is niet zo interessant. Het komt allemaal op hetzelfde neer. Je hebt een source string en die wil je escapen naar een bepaalde output.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Swinnio
  • Registratie: Maart 2001
  • Laatst online: 15:00
flowerp schreef op dinsdag 27 november 2007 @ 22:11:
[...]


Ah kom op joh ;) 1.5 is uit 2004! En 1.4 zelfs uit 2002. Ik weet dat er in het begin een beetje weerstand tegen 1.5 was, maar we zitten nu ruim 3 jaar verder en zelfs 1.6 is al uit.

Aangezien TS met z'n thesis bezig is neem ik aan dat hij gewoon de JDK van de website van Sun heeft gedownload, en dan krijg je alweer een jaar lang automatisch de 1.6 JVM.
Ja, als TS een stand-alone applicatie maakt en verder nergens rekening mee hoeft te houden, is mijn opmerking inderdaad niet van toepassing. :) Maar helaas zijn er ook na 3 jaar nog steeds bedrijven en instellingen die om wat voor reden dan ook nog niet de overstap naar 1.5 hebben gemaakt.
Dat is inderdaad zo. Het is in veel gevallen een micro-optimalisatie. Als je in de gemiddelde app al je StringBuffers door StringBuilders gaat vervangen voorspel ik dat je er inderdaad waarschijnlijk weinig van merkt. Toch is het netter als je voor nieuwe code gewoon default de StringBuilder gebruikt, zeker als het om example code gaat. Er zitten ook voorderest geen enkele nadelen aan StringBuilder ofzo, dus gewoon standaard gebruiken :)
Helemaal mee eens. Wilde het alleen toch even opgemerkt hebben om voor de TS het onderscheid duidelijk te maken tussen wat er nodig is om zijn probleem op te lossen en wat details/optimalisaties zijn. Maar al te vaak lopen topics met relatief simpele problemen uit op principiele discussies over details. Niks mis mee natuurlijk, maar de minder ervaren programmeur loopt dan al snel het risico door de bomen het bos niet meer te zien.

If the world wouldn't suck, we'd all fall off

Pagina: 1