带 Reader 的字符串行或 StringTokenizer?

String line or StringTokenizer with a Reader?

我有一个文件要读取,使用这段代码我成功完成了 JUnit 测试。如您所见,我将字符串行作为参数传递给 readPrevisione(...) 方法。

package oroscopo.persistence;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.StringTokenizer;

import oroscopo.model.Previsione;
import oroscopo.model.SegnoZodiacale;

public class TextFileOroscopoRepository implements OroscopoRepository {

 private HashMap<String, List<Previsione>> mapSettore = new HashMap<>();


public TextFileOroscopoRepository(Reader baseReader) throws IOException, BadFileFormatException{
    if (baseReader == null)
        throw new IllegalArgumentException("baseReader is null");
    BufferedReader bufReader = new BufferedReader(baseReader);
    String line;
    while((line=bufReader.readLine()) != null){
        readPrevisione(line,bufReader);
    }



}

private void readPrevisione(String line, BufferedReader bufReader) throws IOException, BadFileFormatException{
    String nomeSettore = line.trim();
    if (!Character.isUpperCase(nomeSettore.charAt(0)))
        throw new BadFileFormatException();
    List<Previsione> listaPrev = new ArrayList<>();
    while (!(line = bufReader.readLine()).equalsIgnoreCase("FINE")){
        try{
        StringTokenizer st1 = new StringTokenizer(line, "\t");
        if(st1.countTokens() < 2)
            throw new BadFileFormatException();
        String prev = st1.nextToken("\t").trim();
        int val = Integer.parseInt(st1.nextToken("\t").trim());
        Set<SegnoZodiacale> segni = new HashSet<>();
        if (st1.hasMoreTokens()){
            while(st1.hasMoreTokens()){
                try{
                segni.add(SegnoZodiacale.valueOf(st1.nextToken(",").trim()));
                }
                catch (IllegalArgumentException e){
                throw new BadFileFormatException();
                }
            }
            Previsione p = new Previsione(prev,val,segni);
            listaPrev.add(p);   
        }
        else{
            Previsione p2 = new Previsione(prev,val);
            listaPrev.add(p2);  
        }
        }
        catch (NumberFormatException e){
            throw new BadFileFormatException();
        }
        catch (NoSuchElementException e){
            throw new BadFileFormatException();
        }   

    }
    mapSettore.put(nomeSettore, listaPrev); 
}

@Override
public Set<String> getSettori() {
    return mapSettore.keySet();
}

@Override
public List<Previsione> getPrevisioni(String settore) {
    return mapSettore.get(settore.toUpperCase());
    }
}

这里使用相同的代码,而不是将读取的行作为参数传递,而是传递已经读取该行的 StringTokenizer。它应该像上面那样工作,但我的 JUnit 测试失败了。我做错了什么?

package oroscopo.persistence;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.StringTokenizer;

import oroscopo.model.Previsione;
import oroscopo.model.SegnoZodiacale;

public class TextFileOroscopoRepository implements OroscopoRepository {

 private HashMap<String, List<Previsione>> mapSettore = new HashMap<>();


public TextFileOroscopoRepository(Reader baseReader) throws IOException, BadFileFormatException{
    if (baseReader == null)
        throw new IllegalArgumentException("baseReader is null");
    BufferedReader bufReader = new BufferedReader(baseReader);
    String line;
    while((line=bufReader.readLine()) != null){
        StringTokenizer st = new StringTokenizer(line);
        readPrevisione(st,bufReader);
    }



}

private void readPrevisione(StringTokenizer st, BufferedReader bufReader) throws IOException, BadFileFormatException{
    String nomeSettore = st.nextToken().trim();
    if (!Character.isUpperCase(nomeSettore.charAt(0)))
        throw new BadFileFormatException();
    List<Previsione> listaPrev = new ArrayList<>();
    String line;
    while (!(line = bufReader.readLine()).equalsIgnoreCase("FINE")){
        try{
        StringTokenizer st1 = new StringTokenizer(line, "\t");
        if(st1.countTokens() < 2)
            throw new BadFileFormatException();
        String prev = st1.nextToken("\t").trim();
        int val = Integer.parseInt(st1.nextToken("\t").trim());
        Set<SegnoZodiacale> segni = new HashSet<>();
        if (st1.hasMoreTokens()){
            while(st1.hasMoreTokens()){
                try{
                segni.add(SegnoZodiacale.valueOf(st1.nextToken(",").trim()));
                }
                catch (IllegalArgumentException e){
                throw new BadFileFormatException();
                }
            }
            Previsione p = new Previsione(prev,val,segni);
            listaPrev.add(p);   
        }
        else{
            Previsione p2 = new Previsione(prev,val);
            listaPrev.add(p2);  
        }
        }
        catch (NumberFormatException e){
            throw new BadFileFormatException();
        }
        catch (NoSuchElementException e){
            throw new BadFileFormatException();
        }   

    }
    mapSettore.put(nomeSettore, listaPrev); 
}

@Override
public Set<String> getSettori() {
    return mapSettore.keySet();
}

@Override
public List<Previsione> getPrevisioni(String settore) {
    return mapSettore.get(settore.toUpperCase());
    }

}

编辑:这是我想阅读的File.txt

这是我的一个 JUnit 测试示例:

@Test
public void testLetturaCorrettaPrevisioni1() throws IOException, BadFileFormatException {
    Reader mr = new StringReader(
            "NOMESEZIONE\navrai la testa un po' altrove\t\t4\tARIETE,TORO,GEMELLI\ngrande intimita'\t9\nFINE\n"
                    + "SEZIONE2\ntesto di prova\t\t\t\t\t66\t\nFINE");

    OroscopoRepository or = new TextFileOroscopoRepository(mr);

    assertEquals("avrai la testa un po' altrove", or.getPrevisioni("nomesezione").get(0).getPrevisione());
    assertEquals(4, or.getPrevisioni("nomesezione").get(0).getValore());
    Set<SegnoZodiacale> validi = new HashSet<SegnoZodiacale>() {
        private static final long serialVersionUID = 1L;

        {
            add(SegnoZodiacale.ARIETE);
            add(SegnoZodiacale.TORO);
            add(SegnoZodiacale.GEMELLI);
        }
    };
    for (SegnoZodiacale s : SegnoZodiacale.values()) {
        if (validi.contains(s))
            assertTrue(or.getPrevisioni("nomesezione").get(0).validaPerSegno(s));
        else
            assertFalse(or.getPrevisioni("nomesezione").get(0).validaPerSegno(s));
    }

    assertEquals("grande intimita'", or.getPrevisioni("nomesezione").get(1).getPrevisione());
    assertEquals(9, or.getPrevisioni("nomesezione").get(1).getValore());
    for (SegnoZodiacale s : SegnoZodiacale.values()) {
        assertTrue(or.getPrevisioni("nomesezione").get(1).validaPerSegno(s));
    }
}

您正在使用默认分隔符创建 StringTokenizer,即 "the space character, the tab character, the newline character, the carriage-return character, and the form-feed character."

因此,在第一种情况下,您将整行设置为 "nomeSettore" 变量的值,但是当您使用 StringTokenizer.nextToken() 时,您只是将 "nomeSettore" 的值第一个令牌。因此,如果您的字符串 "line" 包含空格,那么 "nomeSettore" 可以有不同的值,并且您的映射中将有不同的键值对。

你可以看看这个例子:

public class TestSO {

public static void main(String[] args) {
    String line = "abcdfs faf afd fa";
    StringTokenizer st = new StringTokenizer(line);
    readPrevisione(st, null);
    readPrevisione(line, null);
}

private static void readPrevisione(StringTokenizer st, BufferedReader bufReader) {
    String nomeSettore = st.nextToken().trim();
    System.out.println(nomeSettore);
}

private static void readPrevisione(String st, BufferedReader bufReader) {
    String nomeSettore = st.trim();
    System.out.println(nomeSettore);
}

}

它打印为输出:

abcdfs
abcdfs faf afd fa

我明白为什么它不起作用了.. 字符串行是:"EXAMPLE\n" 但在

之后
while((line=bufReader.readLine()) != null){
...}

line = "EXAMPLE" 因为 readLine() 会吃掉换行符。 所以我将 StringTokenizer 作为参数

传递给了 readPrevisione()
while((line=bufReader.readLine()) != null){
    StringTokenizer st = new StringTokenizer(line);
    readPrevisione(st,bufReader);
}

private void readPrevisione(StringTokenizer st, BufferedReader bufReader) throws IOException, BadFileFormatException{
String nomeSettore = st.nextToken().trim();
...}

和st.nextToken()搜索不包含在"EXAMPLE"中的\n。这就是它不起作用的原因。