简体   繁体   中英

Iterator implementation is only reading first token in string?

for this program, I need to implement a token iterator that scans from a string and stores a token if it is valid. This seems like an easy process, but my code is only returning the first valid token within the string. Do I need to call hasNext(); in a different location in the next() method?

Here is my code:

public class TokenIter implements Iterator<String>{

    //input line to be tokenized
    private String line;

    // the next Token, null if no next Token
    private String nextToken;

    //Edit
    private Scanner scan;

    public TokenIter(String line){
        this.line = line;
    }

    @Override
    public boolean hasNext() {
        //Edit
        scan = new Scanner(line);
            if(scan.hasNext()){
                nextToken = scan.next();
                return true;
            }
            scan.next();
            nextToken = null;
            return false;
    }

    @Override
    public String next() {
        if(!hasNext()){
            throw new NoSuchElementException();
        }
        else{
            if(nextToken.equals("true")){
                return nextToken;
            }
            if(nextToken.equals("false")){
                return nextToken;
            }
            if(nextToken.equals("or")){
                return nextToken;
            }
            if(nextToken.equals("and")){
                return nextToken;
            }
            if(nextToken.equals("not")){
                return nextToken;
            }
            if(nextToken.equals("(")){
                return nextToken;
            }
            if(nextToken.equals(")")){
                return nextToken;
            }
        }
        return "";      
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

    public static void main(String[] args){
        String line;
        args = Debug.init(args);
        if(args.length>0)
            line = args[0];
        else
            line = " not (true or error false) @# $% ";
        System.out.println("line: [" + line + "]");
        TokenIter tokIt = new TokenIter(line);
        while(tokIt.hasNext()){
            System.out.println("next token: [" + tokIt.next() + "]");
        }
    }

Here is my output of the running program:

line: [ not (true or error false) @# $% ]
next token: [not]
next token: [not]
next token: [not]
next token: [not]
next token: [not]
next token: [not]

This is my desired output:

line: [ not (true or error false) @# $% ]
next token: [not]
next token: [(]
next token: [true]
next token: [or]
next token: [false]
next token: [)]

Your hasNext() method is incorrect, you are scanning the line with every call so you will always return the first token:

 @Override
    public boolean hasNext() {
        Scanner scan = new Scanner(line);
            if(scan.hasNext()){
                nextToken = scan.next();
                return true;
            }
            scan.next();
            nextToken = null;
            return false;

Solution: The variable scan needs to become a class variable so you keep the state between invocations of hasNext() .

As already commented, scanner should be initialized inside the constructor.

Also TokenIter.hasNext() is not the place to set the TokenIter.token, should only return true or false if TokenIter.scan.hasNext() . Assignment should be placed inside TokenIter.next()

additionally, Scanner class uses a delimiter (space by default) so you should wait to catch "(true" as one token. Probably you would like to catch words start with "(" and split them in two tokens inside the overriden TokenIter.next()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM