Avatar billede jonasbc Nybegynder
24. januar 2003 - 11:07 Der er 43 kommentarer og
3 løsninger

Erstatte elementer i String

Hej!

Jeg har brug for at formatere noget HTML-lignende tekst om til en String. Dvs. at tag'et <P> skal erstattes med \n.
Problemet er, at teksten er formateret således:
"bla bla bla.<p> Bla bla..."
Da der ikke er mellemrum mellem tag'et og teksten, kan jeg jo ikke bruge StringTokenizer, der ellers ville have været en elegant løsning.

Hvad gør jeg??
Avatar billede disky Nybegynder
24. januar 2003 - 11:11 #1
1. søg indtil du finder <p> i input
2. kopier text indtil <p> over i StringBuffer
3. indsæt \n i StringBuffer
4. goto 1, indtil du er igennem input
5. lav StringBuffer om til String

Noget i den retning.
Avatar billede soreno Praktikant
24. januar 2003 - 11:11 #2
kan du ikke bare bruge <p> som delimiter og så putte hver token i en stringbuffer med et strategisk velplaceret \n ?
Avatar billede Slettet bruger
24. januar 2003 - 11:12 #3
Java 1.4 har en metode til at erstatte en delstreng med en anden

htmlString.replaceAll( "<p>", "\n");

public String replaceAll(String regex, String replacement)

Replaces each substring of this string that matches the given regular expression with the given replacement.
An invocation of this method of the form str.replaceAll(regex, repl) yields exactly the same result as the expression

Pattern.compile(regex).matcher(str).replaceAll(repl)

Parameters:
regex - the regular expression to which this string is to be matched
Returns:
The resulting String
Throws:
PatternSyntaxException - if the regular expression's syntax is invalid
NullPointerException - if regex is null
Since:
1.4
See Also:
Pattern
Avatar billede disky Nybegynder
24. januar 2003 - 11:15 #4
Gad vide hvordan den replaceAll() performer.
Avatar billede jonasbc Nybegynder
24. januar 2003 - 11:17 #5
disky: tjoo... det kunne være en løsning, men det er ikke så elegant :)
soreno: eksempel?
lts: det skal være kompatibelt med JDK 1.1.8... desværre!
Avatar billede jonasbc Nybegynder
24. januar 2003 - 11:23 #6
disky: kan du evt. omforme det til en metode ala:
String replace(String someText, String oldToken, String newToken) ??
Jeg synes ikke lige, jeg kan få tingene til at hænge sammen i hovedet...
Avatar billede arne_v Ekspert
24. januar 2003 - 11:31 #7
1.4+ brug String's replaceAll.

Før 1.4 brug f.eks. følgende:

public class ReplaceAll {
    public static void main(String[] args) {
        System.out.println(replaceAll("abc<P>123<P>xyz", "<P>", "\n"));
    }
    private static String replaceAll(String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if(ix > 0) {
            String tmp = s.substring(0, ix) + s2 + s.substring(ix + s1.length());
            return replaceAll(tmp, s1, s2);
        } else {
            return s;
        }
    }       
}
Avatar billede soreno Praktikant
24. januar 2003 - 11:44 #8
Eksempel på min løsning:

import java.util.*;

public class Main
{
    public static void main(String args[])
    {
        String input = "<p>Hello<p>World<p>";
        String searchString = "<p>";
        String replacementString = "\n";
        StringBuffer output = new StringBuffer();
        StringTokenizer st = new StringTokenizer(input, searchString);
       
        //nød til at teste om der er en searchString som det første i input.
        if(input.substring(0, searchString.length()).equals(searchString))
        {
            output.append(replacementString);
        }
       
        while(st.hasMoreTokens())
        {           
            output.append(st.nextToken());           
            output.append(replacementString);
        }
        System.out.println(output);
    }
}

Dog havde jeg ikke lige tænkt over situationen hvor <p> er først i strengen, derfor if'en.
Avatar billede jonasbc Nybegynder
24. januar 2003 - 11:45 #9
takker!! det var lige hvad jeg manglede
Avatar billede disky Nybegynder
24. januar 2003 - 11:47 #10
arne:
Din løsning er direkte dårlig !

Man manipulerer ikke på en String, men på en StringBuffer, det performer meget dårligt du du gør.

At du gør det rekursivt giver også et stort memory forbrug, og stak forbrug.
Avatar billede jonasbc Nybegynder
24. januar 2003 - 11:52 #11
så var jeg måske lidt for hurtig med pointene??
disky: har du en løsning, der performace-mæssigt er at foretrække??

programmet skal køre som en batch-proces på en server, så det har noget noget at sige
Avatar billede disky Nybegynder
24. januar 2003 - 11:57 #12
Se dette eksempel:

Det gør ingen forskel på om der står <p> eller <P>

Men ja du var nok lidt for hurtig med point givningen
/*
* SkiftUD.java
*
* Created on 24. januar 2003, 11:11
*/

/**
*
* @author  thygesen
* @version
*/
public class SkiftUD
{
   
    /** Creates new SkiftUD */
    public SkiftUD()
    {
        String in="<p><P>hej<p>med<P>dig<p>";
        String out=replaceAll(in,"<p>","\n");
        System.out.println("in = "+in);
        System.out.println("out= "+out);
    }
   
    private static String replaceAll(String in, String s1, String s2)
    {
        String inUpper=in.toUpperCase();
        String s1Upper=s1.toUpperCase();
        int pos=0;
        int idx;
        int s1Len=s1.length();
        int inLen=in.length();
        StringBuffer out=new StringBuffer();
        while(pos<inLen)
        {
            idx=inUpper.indexOf(s1Upper,pos);
            out.append(in.substring(pos,idx));
            out.append(s2);
            pos=idx+s1Len;
        }
        return out.toString();
    }
   
    /**
    * @param args the command line arguments
    */
    public static void main(String args[])
    {
        new SkiftUD();
    }
   
}
Avatar billede disky Nybegynder
24. januar 2003 - 12:00 #13
Om min løsning eller den med StringTokenizeren er hurtigst, kan jeg ikke lige svare på.

Men den rekursive løsning med brug af String's er klart den langsomste.

p.s. Jeg har ikke testet min med alle mulige input's så jeg garanterer ikke for fejl.
Avatar billede arne_v Ekspert
24. januar 2003 - 12:07 #14
søren prøv og kør din løsning med:
  String input = "<p>xpHello<p>xpWorld<p>";
(hint det virker ikke helt som det skal, da StringTokenizer ikke
bruger strengen som dleimeter men alle chars i strengen som delimiter)
Avatar billede arne_v Ekspert
24. januar 2003 - 12:12 #15
Et eksempel med StringBuffer i.s.f. String.

public class ReplaceAll {
    public static void main(String[] args) {
        System.out.println(replaceAll("abc<P>123<P>xyz", "<P>", "\n"));
    }
    private static String replaceAll(String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if(ix > 0) {
            StringBuffer tmp = new StringBuffer("");
            tmp.append(s.substring(0, ix));
            tmp.append(s2);
            tmp.append(s.substring(ix + s1.length()));
            return replaceAll(tmp.toString(), s1, s2);
        } else {
            return s;
        }
    }       
}
Avatar billede arne_v Ekspert
24. januar 2003 - 12:21 #16
Og det med rekursivitet er noget sludder i dette tilfælde.
Avatar billede soreno Praktikant
24. januar 2003 - 12:27 #17
Nå ja, det gør den da også.
Så har jeg i al den tid jeg har kendt StringTokenizer haft en forkert opfattelse af måden den fungerer på.. chokerende :-)

Men det kunne være smart med en funktion der brugte en (hel) streng som en delimiter.
Avatar billede arne_v Ekspert
24. januar 2003 - 12:29 #18
Jeg har iøvrigt lige testet:

min version med String: 1 million kald/3.5 sek.
min version med StringBuffer: 1 million kald/4 sek.
diskys løsning: crashede (der er ikke en <P> til sidst i mine test-data)
Avatar billede arne_v Ekspert
24. januar 2003 - 12:34 #19
søren> det har du helt ret i.
Avatar billede arne_v Ekspert
24. januar 2003 - 12:36 #20
Og for en god ordens skyld: diskys løsning kan sagtens bringes
til at virke og den vil også være hurtigere.

Men hvormeget vil man kode og teste for hjørne-løsninger for at
bringe tiden ned fra 3.5 milionte-dele sekund til f.eks. 2.5
millionte-dele sekund.
Avatar billede disky Nybegynder
24. januar 2003 - 13:07 #21
arne:
Det er ikke et spørgsmål om hvor meget man vil, det er et spørgsmål om man kender sproget godt nok.

Læs Joshua Bloch's Effective Java, så vil du vide hvorfor.
Avatar billede arne_v Ekspert
24. januar 2003 - 13:10 #22
Følgende løkke ser ud atil at virke:

    private static String replaceAll(String s, String s1, String s2) {
        StringBuffer tmp = new StringBuffer("");
        int ls = s.length();
        int pos = 0;
        while (pos < ls) {
            int ix = s.indexOf(s1, pos);
            if (ix >= 0) {
                tmp.append(s.substring(pos, ix));
                tmp.append(s2);
                pos = pos + (ix - pos) + s1.length();
            } else {
                tmp.append(s.substring(pos));
                pos = ls;
            }
        }
        return tmp.toString();
    }

Og den kører som forventet på 2.5 milionte-del sekund (med
samme test data som de andre).
Avatar billede arne_v Ekspert
24. januar 2003 - 13:18 #23
disky>

Det er et spørgsmål om at levere bang-for-the-buck.

Hvis udviklings-tid og maintenance-tid var gratis, så kunne
man sagtens altid vælge den hurtigste løsning.

Vi ville også stadig kode alt i assembler.

Men tid er penge.

Og derfor er det ofte de simpleste løsninger det er
cost-effective.

Og dit stykke kode illustrerer jo på fortrinlig vis
problematikken.

Det er hurtigt men crasher hvis der ikke er en <P> til sidst.

Det er nemlig lidt bøvlet lige og få den løkke helt rigtig.

Den rekursive løsning kan derimod næsten ikke kodes
forkert.
Avatar billede disky Nybegynder
24. januar 2003 - 13:42 #24
Nej det er ikke bøvlet, måske for dig, men jeg indsatte bare en if() vupti problem væk.

Din løsning er KUN lidt hurtigere hvis men har små korte texter, og performance og server belastning er en MEGET vigtig detalje i den virkelige verden.

Prøv lige og test din metode med www.jp.dk forsiden.

Min bruger:  1793
Din bruger: 46036

Så din er altså meget langsommere

Læg www.jp.dk's forsiden i d:\java\text.txt

Og test selv.

Din metode #2 er klart bedre, men den underbygger jo også mit bevidst for at man IKKE bruger String's til String behandling som du ellers synes var helt okay da det gav value for money. Bare synd den Value er hamrende dårlig performance. Og den anvender heller ikke rekursive kald som bruger en frygtelig masse ram.

P.s. Lad være med at bruge:
pos = pos + (ix - pos) + s1.length();

Inde i den løkke du kører i, hent værdien udenfor, hvorfor ja læs i bogen jeg nævnte.

/*
* SkiftUD.java
*
* Created on 24. januar 2003, 11:11
*/

import java.io.*;

/**
*
* @author  thygesen
* @version
*/
public class SkiftUD
{
   
    /** Creates new SkiftUD */
    public SkiftUD() throws IOException
    {
        String line;
        StringBuffer input=new StringBuffer();
BufferedReader br = new BufferedReader(new FileReader("d:/java/text.txt"));

        while( (line=br.readLine())!=null)
        {
            input.append(line);
        }
    System.out.println("Start");
        String in=input.toString();

        final int antal=1000;

        long start1=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=replaceAll1(in,"<p>","\n");
        }
        long stop1=System.currentTimeMillis();
        System.out.println("Tid for Disky's = "+(stop1-start1));

        long start2=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=replaceAll2(in,"<p>","\n");
        }
        long stop2=System.currentTimeMillis();
        System.out.println("Tid for Arne's #1= "+(stop2-start2));

        long start3=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=replaceAll3(in,"<p>","\n");
        }
        long stop3=System.currentTimeMillis();
        System.out.println("Tid for Arne's #2= "+(stop3-start3));

    }
   
    private static String replaceAll1(String in, String s1, String s2)
    {
        int pos=0;
        int idx;
        int s1Len=s1.length();
        int inLen=in.length();
        StringBuffer out=new StringBuffer();
        while(pos<inLen)
        {
            idx=in.indexOf(s1,pos);
            if(idx==-1) break;
            out.append(in.substring(pos,idx));
            out.append(s2);
            pos=idx+s1Len;
        }
        return out.toString();
    }
   
    private static String replaceAll2(String s, String s1, String s2)
    {
        int ix = s.indexOf(s1);
        if(ix > 0)
        {
            String tmp = s.substring(0, ix) + s2 + s.substring(ix + s1.length());
            return replaceAll2(tmp, s1, s2);
        } else
        {
            return s;
        }
    }
    private static String replaceAll3(String s, String s1, String s2) {
        StringBuffer tmp = new StringBuffer("");
        int ls = s.length();
        int pos = 0;
        while (pos < ls) {
            int ix = s.indexOf(s1, pos);
            if (ix >= 0) {
                tmp.append(s.substring(pos, ix));
                tmp.append(s2);
                pos = pos + (ix - pos) + s1.length();
            } else {
                tmp.append(s.substring(pos));
                pos = ls;
            }
        }
        return tmp.toString();
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) throws IOException
    {
        new SkiftUD();
    }
   
}


Min er svag langsommere ved små strenge, ved store strenge er din håbløst langsom.
Avatar billede disky Nybegynder
24. januar 2003 - 13:47 #25
Sjovt vi efter lidt diskussion kommer frem til ca. ens fungerende metoder, der performer ca. ens.

Men du må da indrømme din den første er et dårligt hack.
Avatar billede arne_v Ekspert
24. januar 2003 - 14:26 #26
disky>

Læs noget mindre i Bloch og lidt mere om elementær algoritme konstruktion.

Din kode virker nemlig ikke !!!!

(hvis der ikke er en <P> til sidst så smider den det sidste tekst væk)
Avatar billede arne_v Ekspert
24. januar 2003 - 14:28 #27
Et glimrende eksempel på, at det kan være meget dyrt at
fin-tune kode, hvis det sker på beskostning af simpelhed.
Avatar billede arne_v Ekspert
24. januar 2003 - 14:29 #28
Og bare for en god ordens skyld, hvis nogen vil bruge noget
af koden der er postet her, så har min terdie løsning ikke
dette problem.
Avatar billede vange_inet Nybegynder
24. januar 2003 - 14:40 #29
Den rekursive metode kan implementeres til at køre hurtigere. Se nedenstående:
public class Test {
    public String replaceAll(String input, String tokenToReplace, String tokenToInsert) {
        StringBuffer sb = new StringBuffer(input.length());
        replaceAllRecursive(sb, input, tokenToReplace, tokenToInsert, 0);
        return sb.toString();
    }

    private void replaceAllRecursive(StringBuffer sb, String input, String tokenToReplace, String tokenToInsert, int beginIndex) {
        final int index = input.indexOf(tokenToReplace, beginIndex);
        if (index >= 0) {
            sb.append(input.substring(beginIndex, index)).append(tokenToInsert);
            replaceAllRecursive(sb, input, tokenToReplace, tokenToInsert, (index + tokenToReplace.length()));
        } else {
            sb.append(input.substring(beginIndex));
        }
    }

    public final static void main(String[] args) {
        Test test = new Test();
        String originalString = "<p>hej<abc<P>123<P><p><p>xyz<<abc<P>123<P>xyz<p>";
        System.out.println(originalString);
        System.out.println(test.replaceAll(originalString, "<p>", "!!!"));
    }
}

For at teste metoden, har jeg tilføjet følgende til SkiftUD-konstruktøren:
    public SkiftUd() throws IOException
    {
        String line;
        StringBuffer input=new StringBuffer();
BufferedReader br = new BufferedReader(new FileReader("c:/text.txt"));

        while( (line=br.readLine())!=null)
        {
            input.append(line);
        }
    System.out.println("Start");
        String in=input.toString();

        final int antal=1000;

        for (int ix=0; ix < 20; ix++) {

        long start1=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=replaceAll1(in,"<p>","\n");
        }
        long stop1=System.currentTimeMillis();
        System.out.println("Tid for Disky's = "+(stop1-start1));

        long start3=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=replaceAll3(in,"<p>","\n");
        }
        long stop3=System.currentTimeMillis();
        System.out.println("Tid for Arne's #2= "+(stop3-start3));

        Test test = new Test();
        long start4=System.currentTimeMillis();
        for(int x=0;x<antal;x++)
        {
            String out=test.replaceAll(in, "<p>","\n");
        }
        long stop4=System.currentTimeMillis();
        System.out.println("Tid for vange's= "+(stop4-start4));
        }
    }

Her mine målinger på JP's forside. Jeg looper 20 gange omkring alle testene. Jeg har fjernet Arne's #1, da den er alt for langsom:
Start
Tid for Disky's = 1266
Tid for Arne's #2= 1000
Tid for vange's= 672
Tid for Disky's = 953
Tid for Arne's #2= 969
Tid for vange's= 593
Tid for Disky's = 1000
Tid for Arne's #2= 953
Tid for vange's= 579
Tid for Disky's = 937
Tid for Arne's #2= 969
Tid for vange's= 562
Tid for Disky's = 953
Tid for Arne's #2= 954
Tid for vange's= 609
Tid for Disky's = 969
Tid for Arne's #2= 937
Tid for vange's= 578
Tid for Disky's = 938
Tid for Arne's #2= 969
Tid for vange's= 765
Tid for Disky's = 1000
Tid for Arne's #2= 969
Tid for vange's= 547
Tid for Disky's = 953
Tid for Arne's #2= 953
Tid for vange's= 672
Tid for Disky's = 937
Tid for Arne's #2= 969
Tid for vange's= 562
Tid for Disky's = 953
Tid for Arne's #2= 954
Tid for vange's= 562
Tid for Disky's = 984
Tid for Arne's #2= 1000
Tid for vange's= 563
Tid for Disky's = 953
Tid for Arne's #2= 953
Tid for vange's= 563
Tid for Disky's = 953
Tid for Arne's #2= 954
Tid for vange's= 562
Tid for Disky's = 938
Tid for Arne's #2= 937
Tid for vange's= 578
Tid for Disky's = 922
Tid for Arne's #2= 953
Tid for vange's= 563
Tid for Disky's = 937
Tid for Arne's #2= 969
Tid for vange's= 578
Tid for Disky's = 984
Tid for Arne's #2= 954
Tid for vange's= 562
Tid for Disky's = 938
Tid for Arne's #2= 953
Tid for vange's= 578
Tid for Disky's = 922
Tid for Arne's #2= 1125
Tid for vange's= 562
Avatar billede disky Nybegynder
24. januar 2003 - 14:42 #30
Nu er Arne's dag redet, efter at være blevet informeret om hans første kode var håbløst langsomt, skal han lige blære sig med han fandt en lille fejl, enhver programmer let kan finde. Men tillykke med det.

Men Arne, hvornår indrømmer du din String/Rekursive løsning IKKE er en value for money løsning som du startede med at snakke om ? Tværtimod er den langsom, bruger en frygtelig masse ram, og folk har det med at lave lort i det når de laver rekursive metoder.

Har lige testet de tre metoder imod hinanden, min vinder stadigvæk i tid, selv med den lille forglemmelse jeg havde.

Men en rigtig udvikler laver koden, derefter retter fejl, til sidst bruger man en profiler til at se hvor tiden bliver brugt, og de metoder der bruger meget tid optimerer man så, hvor din #1 tydeligt ville træde frem. Det er dårlig kotume at optimere under udvikling da man tit bruger tiden de forkerte steder.

p.s. Det er IKKE et spørgsmål om fin tuning, men et spørgsmål om jeg er på arbejde og ikke har tid til at teste mine små eksempler i hoved og røv.
Avatar billede disky Nybegynder
24. januar 2003 - 14:50 #31
Vange:
Din metode ser ud til at være hurtigst, men du har jo heller ikke begået fejlen med at bruge String's istedet for StringBuffer.
Avatar billede disky Nybegynder
24. januar 2003 - 14:52 #32
Hvad angår let læselig hed, er det nok et valg imellem din og min også :)
Avatar billede arne_v Ekspert
24. januar 2003 - 15:05 #33
"folk har det med at lave lort i det når de laver rekursive metoder"

Hvis man læser ovenstående så fremgår det vist klart at jeg lavede en korrekt
rekursiv løsning i løbet af no time, mens du levererede 2 ikke korrekte
non-rekursive løsninger i løbet af flere timer, så jeg har lidt svært
ved at se noget belæg for den påstand.
Avatar billede arne_v Ekspert
24. januar 2003 - 15:14 #34
"bruger en frygtelig masse ram"

Næppe heller.

Den bruger circa 600 bytes per rekursion.
Avatar billede disky Nybegynder
24. januar 2003 - 15:15 #35
<ironi>
Jamen arne du er jo en helt, utroligt du ikke er chef arkitekt hos Sun.

Tag og søg jeg er sikker på Gosling vil overlade sit job til dig.
</ironi>

Siden hvornår kan man lave statistike undersøgelse på en måling ?
Avatar billede arne_v Ekspert
24. januar 2003 - 15:18 #36
Og med hensyn til:

P.s. Lad være med at bruge:
#pos = pos + (ix - pos) + s1.length();
#Inde i den løkke du kører i, hent værdien udenfor, hvorfor ja læs i bogen jeg nævnte.

Så er det en gammeldags programmerings-stil.

Man skal lave sit program så tydeligt som muligt og lade kompileren
(og i Java's tilfælde JVM) om at optimere.

Hint: på SUN JVM 1.3.1 Win32 kører det normalt hurtigere, når man
flytter udenfor, på SUN JVM 1.4.1 Win32 kører det nromalt langsommere
når man flytter udenfor.
Avatar billede arne_v Ekspert
24. januar 2003 - 15:24 #37
Iøvrigt er Gosling idag VP og Fellow hos SUN.
Avatar billede disky Nybegynder
24. januar 2003 - 15:37 #38
Dit program er jo netop ikke tydeligt på den måde, man skal holde linierne så simple som muligt, og ikke +'e og -'e frem og tilbage som du gør.

Selvfølgelig er dette en smagssag, men du nævnte det selv.

Men hvad pokker vi blvier aldrig enig, og du vil sikkert hellere arbejde med String istedet for StringBuffer da det jo giver mere value for money.

God weekend :)
Avatar billede arne_v Ekspert
24. januar 2003 - 15:47 #39
Mit argument i mit 15:05:07 indlæget holder iøvrigt ikke vand,
da der også er fejl i min rekursive løsning !

:-(

(det skal være >= og ikke > !)
Avatar billede arne_v Ekspert
24. januar 2003 - 15:49 #40
Noget helt er iøvrigt at problem-stillingen er "tvivlsom".

I "gammel" HTML skriver man ganske rigtig:
  Afsnit 1
  <P>
  Afsnit 2
  <P>
  Afsnit 3

I nyere HTMl skriver man:
  <P>
  Afsnit 1
  </P>
  <P>
  Afsnit 2
  </P>
  <P>
  Afsnit 3
  </P>
Avatar billede disky Nybegynder
24. januar 2003 - 16:09 #41
Arne:
Det glæder mig du indrømmer du også kan begå fejl :)

Angående hvad man gør har ud ret, men metoden er jo også generel anvendelig :)

Endnu engang god weekend :)

Hilsen
Disky
/Som skal på Ferie messe og se på dykning :)
Avatar billede arne_v Ekspert
24. januar 2003 - 23:07 #42
Muligvis er den oprindelige spørgsmåls-stiller mere forvirret
end godt er over den lidt mudrede debat.

Jeg har lige prøvet at lavet et eksempel som indeholder alle de
forskellige metoder i en form der skulle være korrekt:

public class ReplaceTest {
    private final static int N = 10000;
    public static void main(String[] args) {
        test(new ReplaceRecursiveString());
        test(new ReplaceSmartRecursiveString());
        test(new ReplaceRecursiveStringBuffer());
        test(new ReplaceRecursiveGlobalStringBuffer());
        test(new ReplaceLoopString());
        test(new ReplaceLoopStringBuffer());
        return;
    }
    private static void test(Replacer r) {
        verify(r);
        perf(r);
        return;
    }
    private static void verify(Replacer r) {
        if (!r.replaceAll("123<P>456<P>789", "<P>", "\n").equals("123\n456\n789")
            || !r.replaceAll("<P>123<P>456<P>789<P>", "<P>", "\n").equals("\n123\n456\n789\n")
            || !r.replaceAll("123<P><P>456", "<P>", "\n").equals("123\n\n456")
            || !r.replaceAll("<P>", "<P>", "\n").equals("\n")
            || !r.replaceAll("", "<P>", "\n").equals("")) {
            System.out.println(r.getMethod() + " failed");
        }
        return;

    }
    private static void perf(Replacer r) {
        System.out.println(r.getMethod() + ":");
        perf("short text - few replaces", r, 1000, 5);
        perf("short text - many replaces", r, 1000, 25);
        perf("long text - few replaces", r, 10000, 5);
        perf("long text - many replaces", r, 10000, 25);
        return;
    }
    private static void perf(String title, Replacer r, int txtlen, int nrepl) {
        StringBuffer sb = new StringBuffer("");
        for (int i = 0; i < txtlen; i++) {
            sb.append('A');
            if ((i % (txtlen / nrepl)) == 0) {
                sb.append("<P>");
            }
        }
        perf(title, r, sb.toString());
        return;
    }
    private static void perf(String title, Replacer r, String s) {
        long t1 = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            r.replaceAll(s, "<P>", "\n");
        }
        long t2 = System.currentTimeMillis();
        System.out.println(title + " = " + (t2 - t1));
        return;
    }
}

interface Replacer {
    public String getMethod();
    public String replaceAll(String s, String s1, String s2);
}

class ReplaceRecursiveString implements Replacer {
    public String getMethod() {
        return "Recursive with String";
    }
    public String replaceAll(String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if (ix >= 0) {
            return replaceAll(s.substring(0, ix) + s2 + s.substring(ix + s1.length()),    s1, s2);
        } else {
            return s;
        }
    }
}

class ReplaceSmartRecursiveString implements Replacer {
    public String getMethod() {
        return "Smart recursive with String";
    }
    public String replaceAll(String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if (ix >= 0) {
            return (s.substring(0, ix)    + s2 + replaceAll(s.substring(ix + s1.length()), s1, s2));
        } else {
            return s;
        }
    }
}

class ReplaceRecursiveStringBuffer implements Replacer {
    public String getMethod() {
        return "Recursive with StringBuffer";
    }
    public String replaceAll(String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if (ix >= 0) {
            StringBuffer tmp = new StringBuffer("");
            tmp.append(s.substring(0, ix));
            tmp.append(s2);
            tmp.append(s.substring(ix + s1.length()));
            return replaceAll(tmp.toString(), s1, s2);
        } else {
            return s;
        }
    }
}

class ReplaceRecursiveGlobalStringBuffer implements Replacer {
    public String getMethod() {
        return "Recursive with global StringBuffer";
    }
    public String replaceAll(String s, String s1, String s2) {
        StringBuffer tmp = new StringBuffer("");
        replaceAllHelp(tmp, s, s1, s2);
        return tmp.toString();
    }
    private void replaceAllHelp(StringBuffer res, String s, String s1, String s2) {
        int ix = s.indexOf(s1);
        if (ix >= 0) {
            res.append(s.substring(0, ix));
            res.append(s2);
            replaceAllHelp(res, s.substring(ix + s1.length()), s1, s2);
        } else {
            res.append(s);
        }
        return;
    }
}

class ReplaceLoopString implements Replacer {
    public String getMethod() {
        return "Loop with String";
    }
    public String replaceAll(String s, String s1, String s2) {
        String tmp = new String("");
        int pos = 0;
        while (pos < s.length()) {
            int ix = s.indexOf(s1, pos);
            if (ix >= 0) {
                tmp = tmp + s.substring(pos, ix) + s2;
                pos = ix + s1.length();
            } else {
                tmp = tmp + s.substring(pos);
                pos = s.length();
            }
        }
        return tmp;
    }
}

class ReplaceLoopStringBuffer implements Replacer {
    public String getMethod() {
        return "Loop with StringBuffer";
    }
    public String replaceAll(String s, String s1, String s2) {
        StringBuffer tmp = new StringBuffer("");
        int pos = 0;
        while (pos < s.length()) {
            int ix = s.indexOf(s1, pos);
            if (ix >= 0) {
                tmp.append(s.substring(pos, ix));
                tmp.append(s2);
                pos = ix + s1.length();
            } else {
                tmp.append(s.substring(pos));
                pos = s.length();
            }
        }
        return tmp.toString();
    }
}
Avatar billede disky Nybegynder
24. januar 2003 - 23:13 #43
Hvad siger resultatet ?

Skal dog siges det nok også er værd at teste med store filer :)
Avatar billede arne_v Ekspert
24. januar 2003 - 23:14 #44
Som på min PC giver følgende resultater (SUN JVM 1.3.1 Win32):

Recursive with String:
short text - few replaces = 563
short text - many replaces = 3062
long text - few replaces = 5688
long text - many replaces = 69812
Smart recursive with String:
short text - few replaces = 313
short text - many replaces = 1047
long text - few replaces = 2797
long text - many replaces = 8953
Recursive with StringBuffer:
short text - few replaces = 640
short text - many replaces = 3625
long text - few replaces = 6797
long text - many replaces = 73360
Recursive with global StringBuffer:
short text - few replaces = 218
short text - many replaces = 266
long text - few replaces = 1859
long text - many replaces = 1766
Loop with String:
short text - few replaces = 437
short text - many replaces = 2188
long text - few replaces = 3844
long text - many replaces = 20468
Loop with StringBuffer:
short text - few replaces = 203
short text - many replaces = 250
long text - few replaces = 1828
long text - many replaces = 1657

hvoraf vi ser at:

1) String er meget langsommere end StringBuffer når der er
  mange replacements

2) Rekursion og loop er circa lige hurtigt.
Avatar billede arne_v Ekspert
24. januar 2003 - 23:17 #45
3) Størrelsen på filen har ikke den store betydning.
Avatar billede arne_v Ekspert
24. januar 2003 - 23:18 #46
4) En ikke-global StringBuffer har ikke en positiv effekt
  på de rekursive løsninger.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester