如何使用 Scanner 在 Java 中將輸入作為帶空格的字符串?
一、概述
獲取和解析用戶輸入是我們日常 Java 編程中的一項常見任務,處理包含空格的輸入有時會很棘手。
在本教程中,我們將探討如何使用Scanner
類在 Java 中將輸入作為帶空格的字符串。
二、問題簡介
像往常一樣,讓我們用一個簡單的例子來理解這個問題。
假設我們的掃描器接收到兩行文本。第一個是一個人的名字,第二行是對這個人的簡單描述:
String input = new StringBuilder().append("Michael Jackson\n")
.append("He was the 'King of Pop'.\n")
.toString();
Scanner sc = new Scanner(input);
為簡單起見,我們將向Scanner
對象提供字符串並使用單元測試斷言來驗證結果是否符合預期。
通常,我們會使用Scanner.next()
方法從掃描儀讀取下一個標記。
接下來,讓我們嘗試從我們的掃描儀對像中讀取兩個標記:
String name = sc.next();
String description = sc.next();
assertEquals("Michael", name);
assertEquals("Jackson", description);
如果我們運行測試,它就會通過。顯然, Scanner
並不能智能地理解我們的需求。相反,它使用空格(包括空格和換行符)作為讀取標記的默認分隔符。因此,我們有“ Michael
”而不是“ Michael Jackson
” 作為人名。
實際上,這個例子只展示了一種處理包含空格的輸入值的場景。可能有兩種情況:
- 每行一個值,如我們的“
Michael Jackson
”示例所示 - 由特殊分隔符分隔的值
接下來,我們將了解如何從Scanner
對像中讀取包含空格的值。當然,我們將涵蓋這兩種情況。
3. 每行一個值
讓我們首先仔細看看“每行一個值”的場景。我們仍將使用之前的“ Michael Jackson
”示例作為本節的輸入。
3.1.使用nextLine()
方法
由於我們想從掃描器中讀取整行作為值,因此Scanner's
nextLine()
方法是一個不錯的選擇。 nextLine()
方法從當前位置讀取直到下一個換行符:
Scanner sc = new Scanner(input);
String name = sc.nextLine();
String description = sc.nextLine();
assertEquals("Michael Jackson", name);
assertEquals("He was the 'King of Pop'.", description);
如上面的代碼所示, nextLine()
直接解決了這個問題。
3.2.使用 ' \n
' 作為分隔符
我們之前提到過, Scanner
默認將空格和換行符視為分隔符。如果我們告訴Scanner
只將換行符作為分隔符,我們仍然可以使用next()
方法來讀取一行作為標記。讓我們創建一個測試來驗證它:
Scanner sc = new Scanner(input);
sc.useDelimiter("\\n");
String name = sc.next();
String description = sc.next();
assertEquals("Michael Jackson", name);
assertEquals("He was the 'King of Pop'.", description);
正如我們所見, useDelimiter()
方法是解決問題的關鍵。
4. 由特殊分隔符分隔的值
有時,我們的輸入具有預定義的格式。例如,一個逗號和一個空格分隔三個偉大藝術家名字的輸入行:“ Michael Jackson, Whitney Houston, John Lennon
”。
接下來,讓我們看看如何讀取此場景中的期望值。
4.1.使用String.split()
方法
解決這個問題的第一個想法仍然是使用nextLine().
然後,我們可以將分隔符模式傳遞給方便的String.split()
方法以獲取數組中的值:
String input = "Michael Jackson, Whitney Houston, John Lennon\n";
Scanner sc = new Scanner(input);
String[] names = sc.nextLine().split(", ");
assertArrayEquals(new String[] { "Michael Jackson", "Whitney Houston", "John Lennon" }, names);
上面的測試表明我們已經將三個名字正確地存儲在一個字符串數組中。
4.2.自定義分隔符
帶有分隔符模式方法的split()
可以處理帶有自定義分隔符的值。但是,由於數組在 Java 中具有固定大小,如果掃描儀輸入有多行,合併數組可能會很慢。
通常,我們會在 Java 中使用列表而不是數組。接下來,讓我們調整Scanner's
分隔符並使用Scanner'
的next()
方法將名稱存儲在列表中。
我們已經學會了使用useDelimiter()
方法來設置自定義分隔符模式。由於這個輸入示例的分隔符是逗號和空格,所以我們中的一些人可能會想到: useDelimiter(“, “).
那麼接下來,讓我們在輸入中再添加一個名稱,看看這個想法是否按預期工作:
String input = new StringBuilder().append("Michael Jackson, Whitney Houston, John Lennon\n")
.append("Elvis Presley\n")
.toString();
Scanner sc = new Scanner(input);
sc.useDelimiter(", ");
List<String> names = new ArrayList<>();
while (sc.hasNext()) {
names.add(sc.next());
}
assertEquals(Lists.newArrayList("Michael Jackson", "Whitney Houston", "John Lennon", "Elvis Presley"), names);
如果我們試一試,測試就會失敗。真是個驚喜!因此,讓我們通過幾個斷言弄清楚列表中的內容:
assertEquals(3, names.size());
assertEquals("John Lennon\nElvis Presley\n", names.get(2));
我們可以看到我們的結果列表包含三個元素而不是四個。此外,第三個元素是“John Lennon\nElvis Presley\n”
。這是因為我們設置了“,”作為分隔符。然後,換行符成為令牌的一部分。因此**next()
方法會將換行符視為令牌中的其他常規字符。**
現在我們了解了問題的原因。然後很容易修復——我們必須在分隔符模式中添加“ \n
” :
Scanner sc = new Scanner(input);
sc.useDelimiter(", |\\n");
List<String> names = new ArrayList<>();
while (sc.hasNext()) {
names.add(sc.next());
}
assertEquals(Lists.newArrayList("Michael Jackson", "Whitney Houston", "John Lennon", "Elvis Presley"), names);
這一次,測試通過了。
5.結論
在本文中,我們通過示例學習瞭如何從Scanner
中讀取包含空格的值。這篇文章涵蓋了兩個場景,我們探索了解決問題的不同方法。
與往常一樣,此處提供的所有代碼片段都可以在 GitHub 上找到。