Avatar billede 49152 Nybegynder
30. oktober 2001 - 15:18 Der er 25 kommentarer og
1 løsning

String udskiftning af ord

Er der ikke en enkelt metode til at udskifte en tekst del i en String (eller evt String Buffer);

F.eks. at udskifte alle forekomster af, \"dete\" med \"dette\".

f.eks. ved at skrive noget i stil med

String.replaceAll(\"dete\",\"dette\")

????
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 15:28 #1
Du kunne jo bruge StringTokenizer - eller vente på 1.4 med
regulære udtryk.
Avatar billede 49152 Nybegynder
30. oktober 2001 - 15:33 #2
Jeg kan ikke se hvordan StringTokenizer skulle være mig specielt til hjælp.

Jeg forstår ikke hvad du mener med \"vente på 1.4\"?

VH.
Avatar billede disky Nybegynder
30. oktober 2001 - 15:35 #3
Det er ikke kønt men dette virker:

public class ReplaceAll
{
   
    /** Creates new ReplaceAll */
    public ReplaceAll()
    {
        String in=\"dete er en test, dete\";
        StringBuffer out=new StringBuffer();
       
        int pos=-1;
        int oldpos=0;
       
        while( (pos=in.indexOf(\"dete\",oldpos))!=-1)
        {
            out.append(in.substring(oldpos,pos));
            out.append(\"dette\");
            oldpos=pos+\"dete\".length();
        }
       
        System.out.println(\"in  = \"+in);
        System.out.println(\"out = \"+out.toString());
    }
   
    /**
    * @param args the command line arguments
    */
    public static void main(String args[])
    {
        new ReplaceAll();
    }
   
}
Avatar billede disky Nybegynder
30. oktober 2001 - 15:36 #4
Du kan bruge StringTokenizer men det er lidt overkill.

Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 15:38 #5
Men jeg ser nu ingen grund til at rette \"detektere\" til \"dettektere\", som
din vil gøre disky.
Avatar billede disky Nybegynder
30. oktober 2001 - 15:41 #6
point taken:

Så brug denne her istedet
public class ReplaceAll
{
   
    /** Creates new ReplaceAll */
    public ReplaceAll()
    {
        String in=\"dete er en test, detektere\";
        StringBuffer out=new StringBuffer();
       
        int pos=-1;
        int oldpos=0;
       
        while( (pos=in.indexOf(\"dete \",oldpos))!=-1)
        {
            out.append(in.substring(oldpos,pos));
            out.append(\"dette\");
            oldpos=pos+\"dete \".length();
        }
        out.append(in.substring(oldpos));
       
        System.out.println(\"in  = \"+in);
        System.out.println(\"out = \"+out.toString());
    }
   
    /**
    * @param args the command line arguments
    */
    public static void main(String args[])
    {
        new ReplaceAll();
    }
}

Er dog heller ikke perfekt da den ikke kan lide \'dete,\'

Men ellers hent RegExp og brug regular expressions til det.
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 15:44 #7
Med 1.4 mener jeg bare JDK1.4 :) Her er en anden en med StringTokenizer:

import java.util.*;
class Replace
{
    public static void main(String[] args)
    {
        StringTokenizer s = new StringTokenizer(\"Her er dete som du vil have\",\" ,.:;!?\",true);
        String n=\"\";
        while (s.hasMoreTokens()) {
          String t=s.nextToken();
          if (t.equals(\"dete\")) {
            t=\"dette\";
          }
          if (t.equals(\"ombusmand\")) {
            t=\"ombudsmand\";
          }

          n=n+t;
        }
        System.out.println(n);
    }
}
Avatar billede disky Nybegynder
30. oktober 2001 - 15:46 #8
Det har du ret i, men der er en stor fejl.

String er immutabel og skal IKKE bruges til det du gør, det er håbløst langsomt.

Denne løsning er bedre og hurtigere.

import java.util.*;
class Replace
{
    public static void main(String[] args)
    {
        StringTokenizer s = new StringTokenizer(\"Her er dete som du vil have\",\" ,.:;!?\",true);
        StringBuffer n=new StringBuffer();
        while (s.hasMoreTokens())
        {
            String t=s.nextToken();
            if (t.equals(\"dete\"))
            {
                t=\"dette\";
            }
            if (t.equals(\"ombusmand\"))
            {
                t=\"ombudsmand\";
            }
           
            n.append(t);
        }
        System.out.println(n.toString());
    }
}
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 15:47 #9
Ja ja, disky. Til småtingsafdelingen er det ligegyldigt :)
Avatar billede disky Nybegynder
30. oktober 2001 - 15:49 #10
No way !!

Det er en meget dum holdning at have,

hvis den metode nu skal bruges til at scanne noget text på et par 100 Kb, betyder det UHYGGELIGT meget, prøv selv at mål lidt på det.

Joshua Bloch har i sin fortrinlige bog \'Effective Java\' testet det, forskellen er mere end 1:100 !!
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 15:54 #11
Hvis hr. Bloch påstår at forskellen ER 1:100 ved han vidst ikke hvad han snakker om.
Den kan være 1:10 eller 1:1000 eller.... afhængig af mængden af tekst. Men det er jo
nok bare et eksempel han kommer med. Men til store ting skal man da bruge
StringBuffer - naturligvis.
Avatar billede disky Nybegynder
30. oktober 2001 - 16:02 #12
Erik: undskyld jeg griner men du er ude på MEGET dybt vand.

Du ved ikke hvad du snakker om.


import java.util.*;
class Replace
{
    public static void main(String[] args)
    {
        long start=System.currentTimeMillis();
        for(int x=0;x<1000000;x++)
        {
            String in=\"\";
            in+=\"Test \";
        }
       
        long stop1=System.currentTimeMillis();
       
        for(int x=0;x<1000000;x++)
        {
            StringBuffer buf=new StringBuffer();
            buf.append(\"Test \");
        }
        long stop2=System.currentTimeMillis();
       
        System.out.println(\"Med String      = \"+(stop1-start));
        System.out.println(\"Med StringBuffer = \"+(stop2-stop1));
       
    }
}


På min maskine er String udgaven 2* så længe om det.

Man bruger ALTID StringBuffer hvis der skal ændres det mindste i en String. Hvis ikke er man en slam koder.
Avatar billede disky Nybegynder
30. oktober 2001 - 16:03 #13
Selv når der skal konverteres til en String bagefter vinder StringBuffer.

Og jo mere der skal tilføjes String jo værre bliver det.
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 16:07 #14
Ude på mit dybe vand betyder en faktor 2 ingenting.
Avatar billede disky Nybegynder
30. oktober 2001 - 16:12 #15
dette er tilfældet ved at man KUN tilføjer en gang.

ved 10 gange er den 1:6
ved 100 gange er den 1:15

Skal jeg bliver ved ???

Og da kode forskellen er minimal, er det at bruge en String bare et udtryk for at man er totalt ligeglad med performance i sit software.
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 17:12 #16
Ja, bliv endelig ved, hvis du synes det er sjovt.
Avatar billede logical Nybegynder
30. oktober 2001 - 20:42 #17
Kan I så........... Man kan da heller ikke lade jer være alene et øjeblik.

Jeg tog lige og kompilerede følgende program:

        String a = \"a\";
        int f = 4;
        String c = \"c\";
        String x = null;

        // To slags concat.
        x = a + f + c;
        x = new StringBuffer().append(a).append(f).append(c).toString();

Hvilken en af dem tror I er bedst ??

Her er et uddrag af bytecoden:
--- x = a + f + c;
  11 new #4 <Class java.lang.StringBuffer>
  14 dup
  15 invokespecial #5 <Method java.lang.StringBuffer()>
  18 aload_1
  19 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  22 iload_2
  23 invokevirtual #7 <Method java.lang.StringBuffer append(int)>
  26 aload_3
  27 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  30 invokevirtual #8 <Method java.lang.String toString()>
  33 astore 4
--- x = new StringBuffer().append(a).append(f).append(c).toString();
  35 new #4 <Class java.lang.StringBuffer>
  38 dup
  39 invokespecial #5 <Method java.lang.StringBuffer()>
  42 aload_1
  43 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  46 iload_2
  47 invokevirtual #7 <Method java.lang.StringBuffer append(int)>
  50 aload_3
  51 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  54 invokevirtual #8 <Method java.lang.String toString()>
  57 astore 4

Jeg har også læst Joshua Blochs bog, men han bruger altså en dårlig compiler, som f.eks. suns egen :-)  Spøg til side. Jeg brugte selv Sun 1.3.1 Win32 udgaven.

Der er andre situationer, hvor Bloch har ret i sit punkt, men det er ikke nødvendigvis til daglig.

Et godt råd til jer fra mig (Helt gratis).

Lad være med at kode noget fordi I tror det giver bedre performance. I ødelægger oftere design og forståelighed frem for at lade performance ligge og finde ud af hvor problemerne er. Jeg kender ingen, som har kunnet forudse alle performancebottlenecks på design time, men jeg har set mange brænde meget krudt af uden resultat.
Avatar billede erikjacobsen Ekspert
30. oktober 2001 - 21:07 #18
Hvilket jo blot viser, at i et udtryk med String kan compileren bruge StringBuffer, men
når det aktuelle udtryk er færdigt, konverteres det til String, som sig hør og bør.
Og det er \"dyrt\", ja, hvis man ellers behøver bekymre sig om det.

Hvis man har mere end de to ord \"dete\" og \"ombusmand\" skal man jo nok heller
ikke bare bruge lineær søgning, men f.eks. en HashMap. Men alt det kan man jo
vente med til man ved om det er nødvendigt (hvis refactoring ikke allerede var
opfundet, ville jeg gøre det, haha) - så jeg er grundlæggende enig
med logical. Og det morsomme ved det hele er jo, at jeg også er grundlæggende
enig med disky. Men jeg gider bare ikke skrive så meget i et lille svar om noget
helt andet :)  ...ja, og så gør jeg det alligevel....
Avatar billede disky Nybegynder
31. oktober 2001 - 00:36 #19
logical:

Det gode råd, lyder bestemt som noget jeg hørte på java one, det var vel ikke hr. Bloch :-)

Og hvis du har:

String a=\"hej \";
a+=\"med \";
a+=\"dig \";

f.eks. med kode ind imellem hvordan ser det så ud i forhold til at bruge Stringbuffer ?

Jeg vil give dig og Bloch ret, normalt er det dumt at spilde tid på optimering, men lige i String vs. StringBuffer\'s tilfælde er de rent dovenskab ikke at gøre det. Da StringBuffer i 99 % er hurtigere og aldrig langsommere (ved concatenering)
Avatar billede logical Nybegynder
31. oktober 2001 - 08:09 #20
disky>> Jeg har nu helt mine egne erfaringer på det område, og kunne give det råd endda før J1. Jeg plejer sjældent at genbruge andres råd, hvis jeg ikke selv har kigget problemstillingen igennem (Jeg vil se med fingrene).

Eksemplet ovenpå var et eksempel på, at det ikke altid er til at gennemskue hvad der sker, hvilket betyder at udtryk som \"Man bruger ALTID StringBuffer hvis der skal ændres det mindste i en String. Hvis ikke er man en slam koder\" måske ikke har sin berettigelse. For så er der mange også hos javasoft som er slam kodere :-) (Og så mig selv for øvrigt)

Du er lidt for hurtig ude med riven, selv om du har ret i noget af det du siger. Bloch har et eksempel scenario, hvor han har en faktor 90 på hans maskine ved 100 iterationer med en 80 karakters string. Den er ikke direkte sammenlignelig på min maskine f.eks. Så lad være med at citere noget halvt.

Han har iøvrigt skrevet en enkelt interessant linie:
The morale is simple: Don\'t use the string concatenation operator to combine MORE THAN A FEW strings unless PERFORMANCE IS IRRELEVANT.

Og mht til ALTID at bruge en StringBuffer, skriver du sådan her:

int i = 42;
System.out.println(\"Indholdet er \" + i + \"tilfældigvis\");

eller

int i = 42;
System.out.println(new StringBuffer(\"Indholdet er \").append(i).append(\"tilfældigvis\").toString());

For jeg tager ihvertfald altid den øverste.
Avatar billede logical Nybegynder
31. oktober 2001 - 08:15 #21
Derudover vil jeg til løsning af dette problem hverken bruge String, StringBuffer eller StringTokenizer.

Jeg bruger en ReplacementWriter som jeg selv har skrevet, midt imellem en PrintWriter og en StringWriter, ala dette scenario:

StringWriter sw = new StringWriter();
ReplacementWriter rep = new ReplacementWriter(sw);
PrintWriter out = new PrintWriter(rep);

rep.add(\"dete\", \"dette\");
rep.add(\"ombusmand\", \"ombudsmand\");
rep.add(\"java\", \"Java 2 (TM)\");

out.println(\"Alt min tekst omkring dete java spørgsmål er sendt til vores ombusmand\");
out.flush();
System.out.println(sw.toString());

rep har en intern sorted hashmap, og write parser ind (lidt ligesom StringTokenizer), og laver lookup i hashmap før indhold skrives videre til næste writer.
Avatar billede logical Nybegynder
31. oktober 2001 - 08:18 #22
Som svar på dit spørgsmål:

Nej, man skal gøre det manuelt.
Avatar billede disky Nybegynder
31. oktober 2001 - 09:07 #23
okay altid var måske lidt ofte. (overdrivelse fremmer forståelsen)

Men hvad gør du så hvis du f.eks. skal appende ting til strengen lidt efter lidt altså hvor der foregår anden programmering ind i mellem.

Det er helt korrekt at

int i = 42;
System.out.println(\"Indholdet er \" + i + \"tilfældigvis\");

og

int i = 42;
System.out.println(new StringBuffer(\"Indholdet er \").append(i).append(\"tilfældigvis\").toString());

giver det samme i bytekoden, det står jo i api\'en.

Problemmet er at skal men bag efter tilføje noget mere til strengen på baggrund af noget andet, så skal String udgaven først instantiere en StringBuffer med String som indhold, så appende derefter toString(), næste gang igen instantiere en StringBuffer, så appende så toString() igen osv.

Så bare man skal tilføje noget til en streng to gange, er det langsommere end at bruge StringBuffer.

De eneste tidspunkter jeg ikke bruger StringBuffer er:

1. når jeg generere en String i et huk
2. eksempler til Eksperten
3. jeg eksperimenterer.

Men til kode der skal bruger bruger jeg altid StringBuffer.

En helt anden ting den ReplacementWriter du har lavet er det en man må se ?
Avatar billede logical Nybegynder
31. oktober 2001 - 09:45 #24
Nej :-) Det er ikke en ren open source forretning :-)

Men generelle ideer bag ved
extends FilterWriter
private Map map = new TreeMap();
private String delimiters = \" \\n\\t\\r.,:;!\"#¤%&/()=?+-_\'\";

overskriv write metoder til at se om der er en token, hvis nej gem content.
Hvis ja, hvis vi har en matching key, super.write(value) eller super.write(key)

Avatar billede disky Nybegynder
31. oktober 2001 - 09:48 #25
Det er bare helt okay (jeg regnede heller ikke med det)

Jeg prøver at rode med det selv :)
Avatar billede 49152 Nybegynder
31. oktober 2001 - 11:21 #26
Hej Igen.

Her er en metode som bare gør det, uden så meget snak.. :)

Udskifter alle foremomster af \'from\' med \'to\' i Strengen Str:

public static String replace(String str, String from, String to)

{
  StringBuffer stringBuf  = new StringBuffer(str);
  String returnSt  = new String();
  int i;
  int e;
  i = 0;
  e = str.indexOf(from,i);
  while (e!=-1)
  {
  stringBuf.replace(e, e+from.length() , to);
  i = e+to.length();
  str = new String(stringBuf);
  e=str.indexOf(from, i);
  }
  returnSt = new String(stringBuf);
  return returnSt;
}

vh 49152
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