Avatar billede trp79 Nybegynder
10. april 2004 - 21:07 Der er 14 kommentarer og
1 løsning

regex (pattern og matches)

Hejsa
Jeg har følgende kode:
    Pattern p1 = Pattern.compile("Route length: <b>\\s*((\\d+,\\d+)|(\\d+))\\s*km");
    Matcher m1 = p1.matcher(test);
    while (m1.find())
    {
        Pattern p2 = Pattern.compile("((\\d+,\\d+)|(\\d+))");
        Matcher m2 = p2.matcher(m1.group());
        while (m2.find())
        {
            String match = m2.group();
            match = match.replace(',', '.');
            double value = Double.parseDouble(match);
            System.out.println(value);
        }
    }

Som finder to matches i min string test. Jeg vil egentlig kun have at den skal finde det sidste match.

Her finder den første match:
"København<br>0,6 km<br>01 min. &nbsp;" (det er de 0,6 der er match)
Her finder den anden match:
"<tr>
    <td width=100%>
    Route length: <b>
    0,6    km </b></td>
</tr>"

Hvordan gør jeg så den kun finder sidste match? Jeg ved godt, at den jo bare overskriver den første double, men jeg syntes det er grimt, at den finder et unødigt match.
Hvis nogle kunne forklare hvad de enkelte tegn i det første pattern betyder ville det være forrygende :)
Avatar billede trp79 Nybegynder
10. april 2004 - 21:42 #1
Sikke noget vrøvl. Den finder selvfølgelig ikke match på "København<br>0,6 km<br>01 min. &nbsp;".

Der er dog stadig points til den, der kan forklare lidt om tegnene i det første pattern, og altså kan skære ud i pap hvordan det skal forstås.
Avatar billede trp79 Nybegynder
10. april 2004 - 21:44 #2
Kan man i øvrigt få den til at breake efter førte match, så der ikke bruges yderligere tid på at søge?
Avatar billede arne_v Ekspert
10. april 2004 - 22:53 #3
Route length: <b>    literal
\\s*                  0-mange whitespace
((\\d+,\\d+)|(\\d+))  (1-mange tal + komma + 1-mange tal) eller (1-mange tal)
\\s*                  0-mange whitespace
km                    literal
Avatar billede arne_v Ekspert
10. april 2004 - 22:53 #4
Tja - break laver vel en break ...
Avatar billede trp79 Nybegynder
11. april 2004 - 00:13 #5
Jeg får bare stadig tallet 2 gange når jeg gør som følgende:
    String test = sb.toString();
    Pattern p1 = Pattern.compile("Route length: <b>\\s*((\\d+,\\d+)|(\\d+))\\s*km");
    Matcher m1 = p1.matcher(test);
    while (m1.find())
    {
        Pattern p2 = Pattern.compile("((\\d+,\\d+)|(\\d+))");
        Matcher m2 = p2.matcher(m1.group());
        while (m2.find())
        {
            String match = m2.group();
            match = match.replace(',', '.');
            double value = Double.parseDouble(match);
            System.out.println("value "+value);
            break;
        }
    }

Er det helt i skoven som jeg har placeret break?
Avatar billede arne_v Ekspert
11. april 2004 - 00:17 #6
Jeg tror at med fordel kunne bruge non-capturing group !
Avatar billede arne_v Ekspert
11. april 2004 - 00:17 #7
Men hvis du poster noget input så vil jeg gerne prøve at rette din kode til.
Avatar billede trp79 Nybegynder
11. april 2004 - 00:26 #8
Det vil jeg i hvert fald. Hvad er en non-capturing group?

Her er du så klassen, hvor overstående bliver brugt:
package beregnafstand;
import java.io.*;
import java.net.*;
import java.util.regex.*;
public class Metoder
{
  public Metoder()
  {
  }

  public double ruteAfstand(String fraAdr, String fraPostNr, String tilAdr, String tilPostNr)
  {
    MyUrlEncoder eu = new MyUrlEncoder();
        StringBuffer sb = new StringBuffer("");
    try
    {
      URL url = new URL("http://www.map24.dk/map24/routing.php3?map24_sid=c2e839f7c8ebb988d5b359218551f1a1&rtype=fast&force_maptype=RELOAD&sstreet="+eu.encodeUrl(fraAdr)+"&szip="+eu.encodeUrl(fraPostNr)+"&scountry=dk&dstreet="+eu.encodeUrl(tilAdr)+"&dzip="+eu.encodeUrl(tilPostNr)+"&dcountry=dk");
      InputStream binaerInd = url.openStream();
      BufferedReader ind = new BufferedReader(new InputStreamReader(binaerInd));
      String kilde = ind.readLine();
      while(kilde!= null){
        sb.append(kilde);
        kilde=ind.readLine();
        }
      }
      catch (Exception e) {
      e.printStackTrace();
      }

      String test = sb.toString();
      Pattern p1 = Pattern.compile("Route length: <b>\\s*((\\d+,\\d+)|(\\d+))\\s*km");
      Matcher m1 = p1.matcher(test);
      while (m1.find())
      {
          Pattern p2 = Pattern.compile("((\\d+,\\d+)|(\\d+))");
          Matcher m2 = p2.matcher(m1.group());
          while (m2.find())
          {
              String match = m2.group();
              match = match.replace(',', '.');
              double value = Double.parseDouble(match);
              System.out.println(value);
              return value;
          }
      }
    return -1;
    }
}
Avatar billede arne_v Ekspert
11. april 2004 - 00:35 #9
(?:    )
Avatar billede arne_v Ekspert
11. april 2004 - 00:36 #10
Prøv og kør dette her eksempel:

import java.util.regex.*;

public class NonCapturingRegex {
    private static Pattern p =
        Pattern.compile(
            "(?:Route length: <b>\\s*)((\\d+,\\d+)|(\\d+))(?:\\s*km)");
    public static void findkm(String s) {
        Matcher m = p.matcher(s);
        while (m.find()) {
            System.out.println(m.group(1));
        }
    }
    public static void main(String[] args) throws Exception {
        String s = "København<br>0,7 km<br>01 min. &nbsp;"
                + "<tr>"
                + "<td width=100%>"
                + "Route length: <b>"
                + "0,6    km </b></td>"
                + "</tr>"
                + "København<br>7 km<br>01 min. &nbsp;"
                + "<tr>"
                + "<td width=100%>"
                + "Route length: <b>"
                + "6    km </b></td>"
                + "</tr>";
        findkm(s);
    }

}
Avatar billede trp79 Nybegynder
11. april 2004 - 00:44 #11
Har lige kørt det. Det giver jo også to udskrivninger:( også selvom jeg rettede din string s lidt til, så der stod 6 km ved begge route length.
Avatar billede arne_v Ekspert
11. april 2004 - 00:48 #12
Det skal det jo også - fordi jeg har 2 sæt af samme data.

String s = "København<br>0,7 km<br>01 min. &nbsp;"
                + "<tr>"
                + "<td width=100%>"
                + "Route length: <b>"
                + "0,6    km </b></td>"
                + "</tr>";

bør kun give en enkelt !
Avatar billede arne_v Ekspert
11. april 2004 - 00:49 #13
Pointen var at med en non-capturing group kunne du nøjes med en while løkke.
Avatar billede trp79 Nybegynder
11. april 2004 - 09:58 #14
Okay, så er jeg med :)
Og i denne kan jeg faktisk få brek til at lykkedes. Det må alt andet lige være mere effektivt kun med en while-løkke og med break :)

    public static void findkm(String s) {
        Matcher m = p.matcher(s);
        while (m.find()) {
            System.out.println(m.group(1));
            break;
        }
    }


Mange tak for hjælpen Arne - smid du bare et vel fortjent svar.

Mvh
Torben
Avatar billede arne_v Ekspert
11. april 2004 - 10:30 #15
svar
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