1

我想节省一些时间,而不是手动测试解析文件中的每个标记,但似乎我不知道如何正确使用类的skip(String)方法java.util.Scanner

换个说法:我如何使下面的两个测试都通过?

import java.io.StringReader;
import java.util.Scanner;
import junit.framework.Assert;
import org.junit.Test;

public class ScannerTest {

    static private final String text = "FUNCTION_BLOCK Unnamed_project\n\tVAR_INPUT\n\t\tUnnamed_variable1 : REAL;\n\tEND_VAR\nEND_FUNCTION_BLOCK"; 

    @Test
    public void scannerSkipTest() {

        Scanner sc = new Scanner(new StringReader(text));
        sc.skip("(?i)FUNCTION_BLOCK");
        String blockName = sc.next();
        assert sc.hasNext("(?i)VAR_INPUT");         // added test
        sc.skip("(?i)VAR_INPUT");                               // line of failure
        String variableName = sc.next();
        sc.skip(":");
        String type = sc.next();
        sc.skip("(?i)END_VAR");
        sc.skip("(?i)END_FUNCTION_BLOCK");

        assert "Unnamed_project".equals(blockName);
        assert "Unnamed_variable1".equals(variableName);
        assert "REAL".equals(type);
    }

    @Test
    public void scannerWithoutSkipTest() {
        Scanner sc = new Scanner(new StringReader(text));
        String skipped = sc.next();
        assert "FUNCTION_BLOCK".equalsIgnoreCase(skipped);
        String blockName = sc.next();
        skipped = sc.next();
        assert "VAR_INPUT".equalsIgnoreCase(skipped);
        String variableName = sc.next();
        skipped = sc.next();
        assert ":".equalsIgnoreCase(skipped);
        String type = sc.next();
        skipped = sc.next();
        assert "END_VAR".equalsIgnoreCase(skipped);
        skipped = sc.next();
        assert "END_FUNCTION_BLOCK".equalsIgnoreCase(skipped);

        assert "Unnamed_project".equals(blockName);
        assert "Unnamed_variable1".equals(variableName);
        assert "REAL".equals(type);
    }
}

任何提示和提示表示赞赏。

4

2 回答 2

2

Tuto,感谢您在尝试后编辑我的答案,我将采用您写的内容并在顶部重新编写解释。

基本上,当要跳过带有 的标记时skip(),您需要先跳过空格。相反,该next()方法自动执行此操作。

从javadoc:

next() 和 hasNext() 方法及其原始类型的伴随方法(例如 nextInt() 和 hasNextInt())首先跳过与分隔符模式匹配的任何输入,然后尝试返回下一个标记。

因此,通过使用,sc.skip(WHITESPACE + "abc")您可以跳过任何空格,然后跳过 token abc。结果如下所示:

public class ScannerTest {

    static private final String text = "FUNCTION_BLOCK Unnamed_project\n\tVAR_INPUT\n\t\tUnnamed_variable1 : REAL;\n\tEND_VAR\nEND_FUNCTION_BLOCK";
    public static final String WHITESPACE = "[ \\n\\t]+";

    @Test
    public void scannerSkipTest() {

        Scanner sc = new Scanner(new StringReader(text));
        sc.useDelimiter(WHITESPACE);
        sc.skip("FUNCTION_BLOCK");
        String blockName = sc.next();
        sc.skip(WHITESPACE + "VAR_INPUT");
        String variableName = sc.next();
        sc.skip(WHITESPACE + ":");
        String typeWithSemiColon = sc.next();
        sc.skip(WHITESPACE + "END_VAR");
        sc.skip(WHITESPACE + "END_FUNCTION_BLOCK");

        assert "Unnamed_project".equals(blockName);
        assert "Unnamed_variable1".equals(variableName);
        assert "REAL;".equals(typeWithSemiColon);
    }
}

请注意,扫描仪仍然不会拆分REAL;因为分号并不是真正的空格 - 我把它作为一个练习让你弄清楚:)

于 2013-06-22T11:27:19.743 回答
0

作为参考,我在原始问题上发布了一个更简洁的解决方案,并解决了 vikingsteve 暴露的分号挑战。

这是修正后的测试方法。

笔记:

  • \b由可选空格包围的分隔符
  • 使用方法next而不是skip跳过关键字

@Test
public void scannerSkipTest() {

    Scanner sc = new Scanner(new StringReader(text));
    sc.useDelimiter("\\s*\\b\\s*|\\s+");

    sc.next("(?i)FUNCTION_BLOCK");
    String blockName = sc.next();
    sc.next("(?i)VAR_INPUT");
    String variableName = sc.next();
    sc.next(":");
    String type = sc.next();
    sc.next(";");
    sc.next("(?i)END_VAR");
    sc.next("(?i)END_FUNCTION_BLOCK");

    assert "Unnamed_project".equals(blockName);
    assert "Unnamed_variable1".equals(variableName);
    assert "REAL".equals(type);

    sc.close();
}
于 2013-06-23T11:24:48.687 回答