• 静思
  • 吴言片语
    • 吴言
    • 片语
    • 杂七杂八
  • 死于青春
    • 一路走好
  • 乌合麒麟
  • 纪念
    • 5.12
    • 3.23
  • GitHub
    • A List of Post-mortems
    • The Art of Command Line
  • 关于
    • Privacy Policy

程序员的信仰

金鳞岂是池中物,一遇风云便化龙

HOME » 技术生活 » Scanning Text With java.util.Scanner

Scanning Text With java.util.Scanner

2005 年 1 月 8 日 @ 下午 10:39 by Jay | 被踩了 2,181 脚

J2SE 5.0 adds classes and methods that can make every day tasks easier to perform. In this tip you will see how the newly added java.util.Scanner class makes it easier to read and parse strings and primitive types using regular expressions.

Before the J2SE 5.0 release, you probably wrote code such as the following TextReader class to read text from a file:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.File;

public class TextReader {
    private static void readFile(String fileName) {
        try {
            File file = new File(fileName);
            FileReader reader = new FileReader(file);
            BufferedReader in = new BufferedReader(reader);
            String string;

            while ((string = in.readLine()) != null) {
                System.out.println(string);
            }

            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("usage: java TextReader " + "file location");
            System.exit(0);
        }

        readFile(args[0]);
    }
}

The basic approach in classes like this is to create a File object that corresponds to the actual file on the hard drive. The class then creates a FileReader associated with the file and then a BufferedReader from the FileReader. It then uses the BufferedFile reader to read the file one line at a time.

To view the TextReader class in action, you need to create a document for the class to read and parse. To create the document, save the following two lines of text in a file named TextSample.txt in the same directory as TextReader:

Here is a small text file that you will
use to test java.util.scanner.

Compile TextReader. Then run it by entering the following:

java TextReader TextSample.txt

You should see the original file echoed back to you in standard output.
You can simplify the code in TextReader by using java.util.Scanner, a class that parses primitive types and strings:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class TextScanner {
    private static void readFile(String fileName) {
        try {
            File file = new File(fileName);
            Scanner scanner = new Scanner(file);

            while (scanner.hasNext()) {
                System.out.println(scanner.next());
            }

            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("usage: java TextScanner1" + "file location");
            System.exit(0);
        }

        readFile(args[0]);
    }
}

Compile TextScanner. Then run it as follows:

java TextScanner TextSample.txt

You should get the following output:

Here
is
a
small
text
file
that
you
will
use
to
test
java.util.scanner.

TextScanner creates a Scanner object from the File. The Scanner breaks the contents of the File into tokens using a delimiter pattern, By default the delimiter pattern is whitespace. TextScanner then calls the hasNext() method in Scanner. This method returns true if another token exists in the Scanner’s input, which is the case until it reaches the end of the file. The next() method returns a String that represents the next token. So until it reaches the end of the file, TextScanner prints the String returned by next() on a separate line.

You can change the delimeter that is used to tokenize the input, through the useDelimiter method of Scanner. You can pass in a String or a java.util.regex.Pattern to the method. See the JavaDocs page for Pattern for information on what patterns are appropriate. For example, you can read the input one line at a time by using the newline character (/n) as a delimiter. Here is the revised readFile() method for TextScanner that uses a newline character as the delimiter:

private static void readFile(String fileName) {
    try {
        Scanner scanner = new Scanner(new File(fileName));
        scanner.useDelimiter(System.getProperty("line.separator"));

        while (scanner.hasNext())
            System.out.println(scanner.next());

        scanner.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

Note that there are other options for detecting the end of a line. You could, for example, test for lines that end with a newline character or that end with a carriage return and a newline character. You can do that using the regular expression “/r/n|/n”. The JavaDocs for java.util.regex.Pattern shows other possible line terminators, so a more complete check would use the expression “/r/n|[/r/n/u2028/u2029/u0085]”. You can also use the hasNextLine() and nextLine() methods from the Scanner class. In any case, with the revised TextScanner, the output should match the contents and layout of TextSample.txt. In other words, you should see the following:

Here is a small text file that you will
use to test java.util.scanner.

A simple change of the pattern in the delimiter used by the Scanner gives you a great deal of power and flexibility. For example, if you specify the following delimiter:

scanner.useDelimiter("//z");

it reads in the entire file at once. This is similar to the trick suggested by Pat Niemeyer in his java.net blog. You can read in the entire contents of a web page without creating several intermediate objects. The code for the following class, WebPageScanner, reads in the current contents of the java.net homepage:

import java.net.URL;
import java.net.URLConnection;
import java.io.IOException;
import java.util.Scanner;

public class WebPageScanner {
    public static void main(String[] args) {
        try {
            URLConnection connection = new URL("http://java.net").openConnection();
            String text = new Scanner(connection.getInputStream()).useDelimiter("//Z").next();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

You can handle more than Strings with the Scanner class. You can also use Scanner to parse data that consists of primitives. To illustrate this, save the following three lines in a file named Employee.data (in the same directory as TextSample):

Joe, 38, true
Kay, 27, true
Lou, 33, false

You could still treat this as one large String and perform the conversions after parsing the String. Instead, you can parse this file in two steps. This is illustrated in the following class, DataScanner:

import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

public class DataScanner {
    private static void readFile(String fileName) {
        try {
            Scanner scanner = new Scanner(new File(fileName));
            scanner.useDelimiter(System.getProperty("line.separator"));

            while (scanner.hasNext()) {
                parseLine(scanner.next());
            }

            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void parseLine(String line) {
        Scanner lineScanner = new Scanner(line);
        lineScanner.useDelimiter("//s*,//s*");
        String name = lineScanner.next();
        int age = lineScanner.nextInt();
        boolean isCertified = lineScanner.nextBoolean();

        System.out.println("It is " + isCertified + " that " + name + ", age " + age + ", is certified.");
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("usage: java TextScanner2" + "file location");
            System.exit(0);
        }

        readFile(args[0]);
    }
}

The outer Scanner object in DataScanner reads a file, one line at a time. The readFile() method passes each line to a second scanner. The second scanner parses the comma delimited data and discards the whitespace on either side of the comma. There are variants of the hasNext() and next() methods which enable you to test whether or not the next token is of a specified type and to attempt to treat the next token as an instance of that type. For example, nextBoolean() attempts to treat the next token as a boolean and tries to match it to either the String “true” or the String “false”. If the match cannot be made, a java.util.InputMismatchException is thrown. The parseLine() method of DataScanner shows how each line is parsed into a String, an int, and a boolean.

Compile DataScanner. Then run it as follows:

java DataScanner Employee.data

You should get the following output:

It is true that Joe, age 38, is certified.
It is true that Kay, age 27, is certified.
It is false that Lou, age 33, is certified.

You might be tempted to use just the comma as a delimiter. In other words you might try this:

lineScanner.useDelimiter(",");

This will result in an InputMismatchException. That’s because an extra space will be included in the token that you are trying to convert to a boolean, and the space does not match either “true” or “false”. As is the case with all applications of regular expressions, the underlying power requires that you take extra care in constructing your patterns.

For more information on Scanner, see the formal documentation.


-- EOF --

除非注明(如“转载”、“[zz]”等),本博文章皆为原创内容,转载时请注明: 「转载自程序员的信仰©」
本文链接地址:Scanning Text With java.util.Scanner

分享

  • 点击分享到 Facebook (在新窗口中打开) Facebook
  • 点击以分享到 X(在新窗口中打开) X
  • 更多
  • 点击分享到Reddit(在新窗口中打开) Reddit
  • 点击分享到Telegram(在新窗口中打开) Telegram
  • 点击以在 Mastodon 上共享(在新窗口中打开) Mastodon

赞过:

赞 正在加载……

相关

Posted in: 技术生活 Tagged: java
← 庆祝一下
在Java中使用Oracle blob →

android (9) apple (20) augmentum (9) Beijing (21) bt (8) career (28) coding (38) firefox (10) google (36) hibernate (11) ibm (11) iphone (10) java (93) linux (16) m$ (26) mac (58) macos (27) nazca (9) olympics (8) oo (8) playstation (10) rip (8) Shanghai (39) spring (9) tips (45) tommy emmanuel (8) ubuntu (12) usa (23) windows (9) 北航 (17) 博客 (29) 吐槽 (8) 周末 (9) 和谐社会 (26) 小资 (11) 愤青 (40) 方言 (10) 朋友 (77) 歌词 (8) 烟酒不分家 (18) 爱国 (19) 爱情 (8) 犯二 (15) 破解 (8) 足球 (11)

烫手山芋

  • 再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~ - 被踩了 27,349 脚
  • 生活,就是一个期待跟着一个期待 - 被踩了 21,357 脚
  • 星巴克饮品缩写大全(Starbucks Drink ID Codes)[zz] - 被踩了 18,408 脚
  • 从一个全角冒号说一下我为什么不感冒iOS - 被踩了 14,317 脚
  • 有关Character.isLetter()和Character.isLetterOrDigit() - 被踩了 13,591 脚

刚拍的砖

  • leo 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》
  • 花 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》
  • 无名氏 发表在《从一个全角冒号说一下我为什么不感冒iOS》
  • Jay 发表在《Mac OS geek级问题》
  • Wei Wang 发表在《再谈苹果的输入法:这一次是靠OS X自带的输入法来翻身的~》

随便看看

  • 新的开始11 年 ago
  • Tommy来了,你却走了9 年 ago
  • 80后的特征,你符合几条?(二)[zz]19 年 ago
  • JFreeChart中的TimeSeries可能导致内存泄露9 年 ago
  • Regain my honor20 年 ago

文以类聚

光阴似箭

其他操作

  • 登录
  • 条目 feed
  • 评论 feed
  • WordPress.org

Copyright © 2025 程序员的信仰.

Jay's Omega WordPress Theme by Jay

 

正在加载评论...
 

    %d