Toon posts:

Tab negeren in nextLine() (JAVA)

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb de onderstaande invoer:
code:
1
2
woord1 woord1   een twee drie
woord2 woord2   een twee drie

Waarbij bijvoorbeeld in de eerste regel deel A bestaat uit alles dat voor de tab komt, dus woord1 woord1, en deel B bestaat uit uit alles dat na de tab komt in de eerste regel, dus een twee drie. Dat geldt ook voor regel 2, etcetera.

Nu wil ik bij het inlezen, woord1 woord1 in één string stoppen, en een twee drie in een andere string (dus alles wat voor en nà de tab komt dient in een string te komen waarbij de tab zelf buitengesloten wordt. Daarvoor had ik de onderstande code geschreven:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Koppelen{
    
    PrintStream out;
    
    public Koppelen(){
        InputSelector.selectFile();
        out = new PrintStream(System.out);
    }
    public void start() {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()){
                in.useDelimiter("\t");
                String deelA = in.next();
                String deelB = in.nextLine();
                out.printf("Deel A: " + deelA + " Deel B: " + deelB + "\n");
        }   
    }
    public static void main (String[] argv) {
        new Koppelen().start();
    }
}


MAAR wat gebeurt er? Ik krijg deze uitvoer:

code:
1
2
Deel A: woord1 woord1 Deel B:   een twee drie
Deel A: woord2 woord2 Deel B:   een twee drie


Maw, de tab wordt meegenomen bij nextLine()! (zie lege ruimte tussen Deel B en een twee drie hierboven in de uitvoer. Hoe kan dit nou? Ik heb toch niet voor niets die delimiter op een tab ingesteld? En hoe kan ik die tab weglaten? Ik wil dat uitsluitend een twee drie in een string worden gestopt.

Ik heb next() geprobeerd ipv nextLine(), alleen dat gaf al helemaal gekke resultaten, de volgende regel werd er namelijk ook in betrokken :'(

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Is 't niet zoiets?
Java:
1
in.useDelimiter("\t|\n");

En dan 2x .next() gebruiken i.p.v. .next() en .nextline()

Edit: Even Netbeans geïnstalleerd (doe nooit iets met Java) en getest...
Java:
1
2
3
4
5
6
7
    public static void main(String[] args) {
        Scanner in = new Scanner("A B\tC D\nE F\tG H\n").useDelimiter("\t|\n");
        while (in.hasNext()){
                System.out.println(in.next());
                System.out.println(in.next());
        }
    }

Output:
A B
C D
E F
G H

Voila. En zo moeilijk was dat niet te vinden. Er staat in de documentatie dat je een pattern specificeert met usedelimiter.

Overigens vind ik het sowieso vreemd om useDelimiter in de while lus te zetten; dan ga je er bij de eerste .hasNext() al van uit dat je matched op whitespace* (wat in jouw situatie toevallig goed is) en daarna zet je, onnodig, iedere iteratie de usedelimiter opnieuw.
* A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace
Een heleboel zaken had je gewoon prima zelf kunnen uitsluiten door simpel te debuggen (Debuggen: Hoe doe ik dat?).

[ Voor 255% gewijzigd door RobIII op 22-07-2010 01:17 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Verwijderd

Ik neem aan dat dit bestandje puur ter configuratie zal dienen? Waarom niet gewoon een bestand gescheiden door: ';' of '|' (.csv) of een XML file en deze naar een object serializen, dit werkt stukken prettiger aangezien je alle data dan lekker een object hebt zitten.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Yes! Dankzij de hulp van Rob ben ik weer een stapje verder, het werkt prima nu.

De documentatie had ik er weldegelijk op nageslagen, alleen ik had niet kunnen vinden dat je in één keer meerdere delimiters kon opgeven, vandaar dat ik het inlezen van de rest van de regel (en vervolgens overgaan tot de volgende regel) met een nextLine wilde oplossen, alleen toen pakte hij die tab steeds mee... :'( In ieder geval, weer wat geleerd, ontzettend bedankt _/-\o_

Het punt is alleen, ik zit nou weer voor een obstakel. Laten we zeggen de invoer bestaat uit:

code:
1
2
een twee drie   een twee drie
vier vijf zes    een twee drie


Nu wil ik checken op iedere regel of string deel A gelijk is aan string deel B, dus een twee drie is gelijk aan een twee drie. Aangezien beide delen een string betreft, dacht ik dit simpel op te lossen met deelA.equals(deelB)...

code:
1
2
3
if (deelA.equals(deelB)) {
    out.printf("Het werkt!");
}


Maar om de één of andere manier is dit altijd false, niet zoals verwacht op de 2e regel van de invoer (zie boven) maar ook gewoon op de eerste regel...

Ik had al wat rondgesnuffeld op internet, en het zou in principe moeten werken als ik dit zo lees:
Use the equals() method to compare object values. The equals() method returns a boolean value. The previous example can be fixed by writing:

code:
1
if (name.equals("Mickey Mouse"))  // Compares values, not refererences.


Because the equals() method makes a == test first, it can be fairly fast when the objects are identical. It only compares the values if the two references are not identical.
Alleen vervang ik "Mickey Mouse" door een string variabele... 8)7 So what?
Verwijderd schreef op donderdag 22 juli 2010 @ 00:29:
Ik neem aan dat dit bestandje puur ter configuratie zal dienen? Waarom niet gewoon een bestand gescheiden door: ';' of '|' (.csv) of een XML file en deze naar een object serializen, dit werkt stukken prettiger aangezien je alle data dan lekker een object hebt zitten.
Hmm, wijsheid komt achteraf natuurlijk. Ik was een beetje impulsief te werk gegaan om eerlijk te zijn :F

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op donderdag 22 juli 2010 @ 10:31:
Maar om de één of andere manier is dit altijd false, niet zoals verwacht op de 2e regel van de invoer (zie boven) maar ook gewoon op de eerste regel...
Debuggen, debuggen, debuggen, debuggen, debuggen, debuggen...
Java:
1
2
3
4
5
6
7
8
    public static void main(String[] args) {
        Scanner in = new Scanner("A B\tA B\nE F\tG H\n").useDelimiter("\t|\n");
        while (in.hasNext()){
                String A = in.next();
                String B = in.next();
                System.out.println(A.equals(B));
        }
    }

true
false

Je doet dus ergens iets niet goed. Zorg maar eens dat A én B precies bevatten wat je verwacht (en dus niet nog ergens whitespace bevatten ofzo), dat je de (waar nodig) juiste compare gebruikt etc..

[ Voor 58% gewijzigd door RobIII op 22-07-2010 11:17 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • RedRose
  • Registratie: Juni 2001
  • Niet online

RedRose

Icebear

Kan je niet beter gewoon een Stream gebruiken, per newline een regel inlezen en dan simpel een string.split("\\t") doen ?

Sundown Circus


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Die trim functie did the job! Bedankt Rob!!! _/-\o_ _/-\o_ Je bent me enorm hulpvaardig geweest!
RedRose schreef op donderdag 22 juli 2010 @ 11:30:
Kan je niet beter gewoon een Stream gebruiken, per newline een regel inlezen en dan simpel een string.split("\\t") doen ?
Dat zou ook kunnen inderdaad, maar ik ben daar nog niet echt bekend mee, wilde liever te werk gaan met de stof die ik tot op zekere hoogte al onder de knie had,

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb die trim functie maar even weer weggehaald omdat ik vind dat het ook zonder zou kunnen.

Het blijft me werkelijk waar verbazen, de code is prima, en toch blijft de uitvoer merkwaardige resultaten geven:

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
25
public class Inlezen{
    
    PrintStream out;    
    File file1;
    
    public Inlezen(){
        out = new PrintStream(System.out);
        file1 = new File("Test.txt");
    }

    public void start() throws FileNotFoundException {
        Scanner in = new Scanner(file1);
        in.useDelimiter("\t|\n");
        while (in.hasNext()){
            String deel1 = in.next();
            String deel2 = in.next();
            out.printf(""+deel1+" "+deel2);
        }
    }
    
    public static void main (String[] argv) throws FileNotFoundException {
        new Inlezen().start();
    }
    
}


Met als invoer:

code:
1
2
3
4
5
6
lakenstof   sheeting
Assepoester Cinderella
Nederlander resident of the Netherlands
Hebreeuws   Hebrew
Indische olifant    Indian elephant
Assyrisch   Assyrian


Alle woorden met hun Engelse vertalingen zijn gescheiden met een tab.

En dan krijg ik verdomme dit als resultaat:

code:
1
2
3
4
5
6
lakenstof sheeting
 AssepoesterCinderella
Nederlander resident of the Netherlands
 HebreeuwsHebrew
Indische olifant Indian elephant
 AssyrischAssyrian


Het gaat mij met name om die spaties die bij het begin van sommige woorden (Assepoester) verschijnen en vervolgens worden de desbetreffende woorden aan elkaar worden geplakt (AssepoesterCinderella), het gaat om de regel zo, en ik weet in hemelsnaam niet waarom dit gebeurt. De ene regel is prima, de ander weer niet.

Zou er iets mis zijn met de invoer?

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ga...nou...eens...de-bug-gen :|
Honestly; je kunt hier alleen iets over zeggen als je fatsoenlijk debugged. De trim had wel degelijk een effect en met het weghalen van die trim is het weer stuk. Dus zoek uit wat die trim precies wel/niet verwijdert en je bent al een heel eind. En anders druk de waardes eens af tussen blokhaken bijvoorbeeld:
Java:
1
            out.printf("["+deel1+"]<"+deel2+">"); 

Dan krijg je iets als [ appel]<apple > en zie je automatisch waar je (onverwachtte) whitespace zit etc. En mocht er whitespace in voorkomen die niet afgedrukt wordt of die je om andere redenen niet zou zien dan helpt het ook als je iedere match even door een dump-functie haalt die gewoon teken voor teken de ascii-waarde even print.
A  65
p  112
p  112
e  101
l  108
   9


Dit soort output. En als het dan nog niet werkt, stap dan stap-voor-stap met je debugger door de code en zet watches op variabelen, haal je input(file) door een hexeditor of weet ik het maar for Pete's sake; kom van je luie r**t af en sla aan het debuggen. We kunnen hier geen handjes (blijven) vasthouden. Ik verzin zo, terplekke, al 5 mogelijke manieren om je probleem te lijf te gaan; je maakt me niet wijs dat je er geen een zelf had kunnen verzinnen als je niet heel even had nagedacht.
Debuggen: Hoe doe ik dat?

[ Voor 51% gewijzigd door RobIII op 27-07-2010 00:47 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ok, ik ben dus aan het debuggen geslagen (inclusief het deel met de ASCII waarden, maar daaruit kon ik niks opmaken).

Dit was mijn invoer:

code:
1
2
3
Assepoester Cinderella
Assepoester Cinderella
Assepoester Cinderella


En het programma:

Java:
1
2
3
4
5
6
7
8
9
public void start() throws FileNotFoundException {
        Scanner in = new Scanner(file1);
        in.useDelimiter("\t|\n");
        while (in.hasNext()){
            String deel1 = in.next();
            String deel2 = in.next();
            out.printf("["+deel1+"]<"+deel2+">"+"\n");
        }
    }


Kreeg ik dit als uitvoer:

code:
1
2
3
4
5
6
[Assepoester]<Cinderella>
[
]<Assepoester>
[Cinderella]<
>
[Assepoester]<Cinderella>


Blijkbaar werd er na iedere regel toch iets ingelezen dat daar niet hoort...

Dus ik dacht, ik voeg er een extra String deel3 = in.next(); aan toe in de while-loop om dat op te vangen.

En nu is de uitvoer:

code:
1
2
3
[Assepoester]<Cinderella>
[Assepoester]<Cinderella>
[Assepoester]<Cinderella>


Yeeeeeeey!!! _/-\o_

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op dinsdag 27 juli 2010 @ 11:41:
(inclusief het deel met de ASCII waarden, maar daaruit kon ik niks opmaken).
Onzin; dan had je geheid iets gezien als:
C 67
i 105
n 110
d 100
e 101
r 114
e 101
l 108
l 108
a 97 

13 <--DEZE
Waar zijn die ASCII waardes dan? Je dumpt nu alleen je matches en je kunt nu zien dat er iets gematched wordt wat je niet wou matchen. Niets meer dan dat.
Verwijderd schreef op dinsdag 27 juli 2010 @ 11:41:
Blijkbaar werd er na iedere regel toch iets ingelezen dat daar niet hoort...
Als je \r\n gebruikt als regeleindes (wat gebruikelijk is in windows maar niet in Linux en andere OS-en) en de scanner vertelt dat je \t en \n zoekt, wat zou je dan nog tegenkomen? Juist: een \r
Verwijderd schreef op dinsdag 27 juli 2010 @ 11:41:
Dus ik dacht, ik voeg er een extra String deel3 = in.next(); aan toe in de while-loop om dat op te vangen.
En je haalt de trim weg omdat je die overbodig vindt maar een .next() in een loze, ongebruikte variabelen mikken niet? :F

Verder: Als je mijn voorbeeld even had gehanteerd voor je input, dus:
Java:
1
Scanner in = new Scanner("Assepoester\tCinderella\nAssepoester\tCinderella\n").useDelimiter("\t|\n");

dan had je gezien dat de code gewoon prima werkt en dat je probleem dus in je bestand moest zitten.

Van de 5 mogelijkheden die ik je gaf probeer je de simpelste welke niet meteen (voor jou) duidelijk maakt wat het probleem is en vervolgens laat je het daar bij en knal je maar een .next() erbij :X

[ Voor 33% gewijzigd door RobIII op 27-07-2010 12:22 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Pagina: 1