24. januar 2003 - 11:07Der 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.
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
kan du ikke bare bruge <p> som delimiter og så putte hver token i en stringbuffer med et strategisk velplaceret \n ?
Synes godt om
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
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
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...
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); }
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)
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)
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.
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"));
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(); }
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"));
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
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.
"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.
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.
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
4) En ikke-global StringBuffer har ikke en positiv effekt på de rekursive løsninger.
Synes godt om
Ny brugerNybegynder
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.