Scanner.hasNext(模式)无法按预期运行

时间:2018-11-05 21:15:06

标签: java regex java.util.scanner

我正在使用Scanner类来解析一些文本。也许我的模式是错误的,但是我尝试对其进行调整,但没有找到使其工作的方法,所以我将其发布在这里:

public class StackOverflowExample {
    public static void main(String[] args) {
        // This is a source string example
        StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
        // The scanner instance with default values
        Scanner scanner = new Scanner(stringReader);
        // Set the scanner delimiter to \b* so it takes blanks as delimiters only if they're there
        scanner.useDelimiter(Pattern.compile("\b*"));
        // Compile the pattern to match field names
        Pattern field_name_pattern = Pattern.compile("\"\\w+\":");
        // Check if scanner finds the first field name
        if (scanner.hasNext(field_name_pattern)) {
            // Field name found, so print it
            System.out.println(scanner.next(field_name_pattern));
        } else {
            // Field name not found, so warn about it
            System.out.println("Oops! It didn't work!");
        }
    }
}

预期的行为是扫描程序与读取器中的第一个“ field_name”:子字符串匹配,因此对扫描程序返回true。hasNext(field_name_pattern),但实际行为是它与之不匹配,因此返回改为false。

3 个答案:

答案 0 :(得分:2)

问题出在扫描仪的定界符中,该问题失败,并且将完整的输入字符串作为下一个令牌返回给扫描仪,并导致模式public function getPosts() { return $this->hasMany(Post::className(), ['id' => 'post_id']) ->viaTable('post_tag',['tag_id'=>'id']); } 返回"\"\\w+\":"

根据public boolean hasNext​(Pattern pattern)的Javadoc

  

如果下一个完整令牌与指定的模式匹配,则返回true。完整的令牌由与定界符模式匹配的输入作为前缀和后缀。

您可能希望使用冒号作为分隔符以使其起作用:

false

完整代码:

scanner.useDelimiter(Pattern.compile(":"));

输出:

// This is a source string example
StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
// The scanner instance with default values
Scanner scanner = new Scanner(stringReader);
// Set the scanner delimiter to \b* so it takes blanks as delimiters only if they're there
scanner.useDelimiter(Pattern.compile(":"));
// Compile the pattern to match field names
Pattern field_name_pattern = Pattern.compile("\"\\w+\"");
// Check if scanner finds the first field name
if (scanner.hasNext(field_name_pattern)) {
    // Field name found, so print it
    System.out.println(scanner.next(field_name_pattern));
} else {
    // Field name not found, so warn about it
    System.out.println("Oops! It didn't work!");
}
scanner.close();

答案 1 :(得分:1)

Scanner将文本分成令牌,然后提供这些令牌或允许您使用这些令牌。分隔符是确定如何将令牌分开的因素。来自Javadoc

  

扫描程序使用定界符模式将其输入分为令牌,默认情况下,该模式与空格匹配。然后,可以使用各种下一种方法将生成的令牌转换为不同类型的值。

在您的情况下,分隔符为"\b*"。使用这样的可选定界符,我不确定Scanner会做什么,但是您的测试表明,它会将无空格的文本拆分为与指定模式不匹配的单个标记。

如果您想为此使用Scanner,则必须找到一种与您的用例更好地结合的模式。如果这更适合您的用例,那么您也可能只使用正则表达式而不使用扫描器。

答案 2 :(得分:0)

好的,其他用户指出的问题是,当没有具体的定界符时,Scanner.hasNext(Pattern pattern)方法不起作用。实际上,它需要它来生成令牌,否则,整个字符串将成为下一个令牌。

解决方案是改用Scanner.findInLine(Pattern pattern)方法,如下所示:

public class StackOverflowExample {
    public static void main(String[] args) {
        // This is a source string example
        StringReader stringReader = new StringReader("\"field_name\":\"field_value\"");
        // The scanner instance with default values
        Scanner scanner = new Scanner(stringReader);
        // Compile the pattern to match field names
        Pattern field_name_pattern = Pattern.compile("\"\\w+\":");
        // Check if scanner finds the first field name
        String field_name = scanner.findInLine(field_name_pattern);
        if (field_name != null) {
            // Field name found, so print it
            System.out.println(field_name);
        } else {
            // Field name not found, so warn about it
            System.out.println("Oops! It didn't work!");
        }
    }
}

非常感谢那些回答。