对于这个任务,规范很简单。您将获得一个任意长度的文本文件(可能有数千个字符)。要被认为是正确的,它必须包含匹配的括号对{ }
,[ ]
和( )
。括号对可以嵌套到任意深度(但不会太深以至于您需要担心堆栈溢出),括号之间的文本数量是任意的。不包含括号的文件是非常正确的。当您发现一对不匹配的括号时,您必须在文件中报告括号及其索引。文件中的第一个字符是索引 0。例如,如果文件包含此文件,则该文件有一个打开{ and another { followed by ) and }
和一些文本。您的程序应该报告不匹配,因为{ at index 36 is closed by the )
at 索引 50。您可以将文件的开头视为超级opening bracket
不匹配任何右括号。如果文件包含太多右括号,则不匹配opening bracket
的是文件的开头。您应该使用字符串STX
(旧 ascii start of text
)来报告这一点。例如,此关闭 ] 没有匹配的打开 [。在这种情况下,您的程序应该报告不匹配,因为索引 -1 处的 STX 被]
索引 13 处关闭。类似地,您可以将文件末尾视为closing bracket
不匹配任何左括号的超级。一个文件可能包含太多的左括号。报告这一点,就好像不匹配closing bracket
确实是文件末尾之后的(不存在的)右括号。例如,这个 open ( 没有匹配 将其重新报告为不匹配,因为(
在索引 10 处由索引 24 处的 EOF 关闭。您的任务是编写两个方法,一个递归方法 recursiveMatch 和一个迭代方法 iterativeMatch 来处理文件并检查括号是否匹配。当任一方法检测到括号不匹配时,它应该抛出类 Matchfail 的异常。Matchfail 对象中的信息应包括文件中不匹配的括号及其索引。
这是我到目前为止的代码:
import java.io.File ;
import java.io.FileReader ;
import java.io.IOException ;
/**
* Development driver for Assignment #4, matching brackets.
*
* @author lou
* @param args[0]
* name of a file to check
*/
public class Assign4 {
public static void main(String[] args) {
/*
* Check that the user has supplied a file name, and that the file
* exists and is readable.
*/
if (args.length <= 0) {
System.out.println("Usage: java Assign4 <filename>") ;
System.exit(1) ;
}
String fileName = args[0] ;
File handle = new File(fileName) ;
if (!(handle.exists() && handle.canRead())) {
System.out.println("Please check that file \"" + fileName
+ "\" exists and is readable.") ;
System.exit(2) ;
}
/*
* Create an input stream of type FileReader to read the file character
* by character. This can throw a (checked) IOException so we need to
* wrap it in a try/catch block.
*
* It's good practice to always close a FileReader to avoid
* a resource leak (resources that are allocated but not released). If
* src is not null, resources may have been allocated even if creation of
* the FileReader fails and we should attempt a close to free them.
* Closing a file reader can itself throw an IOException, so we need a
* nested try/catch block.
*/
FileReader src = null ;
try {
src = new FileReader(handle) ;
} catch (IOException ex) {
System.out.println("Exception while opening file \"" +
fileName + "\" for read.") ;
System.out.println("Exception: " + ex) ;
try {
if (src != null) src.close() ;
} catch (IOException closeEx) {
System.out.println(
"Exception while closing file \"" + fileName + "\".") ;
System.out.println("Exception: " + closeEx) ;
}
System.exit(3) ;
}
/*
* Try the recursive match method first. A MatchFail exception is
* certainly a possibility. Allow that other exceptions might be thrown
* but don't attempt to do anything.
*/
MatchBrackets matcher = new MatchBrackets() ;
try {
matcher.recursiveMatch(src) ;
System.out.println("Brackets match (recursive)!") ;
} catch (MatchFail ex) {
System.out.println("A bracket on its own is up to no good!") ;
System.out.println(ex) ;
} catch (Exception ex) {
System.out.println("Unexpected exception "+ex) ;
}
/*
* We need to return to the beginning of the file to test the iterative
* match. For a FileReader, this requires closing and reopening the file.
*/
try {
System.out.println("Attempting close and reopen.") ;
src.close() ;
src = new FileReader(handle) ;
} catch (IOException ex) {
System.out.println("Exception while reopening file \"" + fileName
+ "\" for read.") ;
System.out.println("Exception: " + ex) ;
try {
if (src != null) src.close() ;
} catch (IOException closeEx) {
System.out.println(
"Exception while closing file \"" + fileName + "\".") ;
System.out.println("Exception: " + closeEx) ;
}
System.exit(3) ;
}
/*
* Try the iterative match method.
*/
try {
matcher.iterativeMatch(src) ;
System.out.println("Brackets match (iterative)!") ;
} catch (MatchFail ex) {
System.out.println("A bracket on its own is up to no good!") ;
System.out.println(ex) ;
} catch (Exception ex) {
System.out.println("Unexpected exception "+ex) ;
}
/*
* Close the file and we're done.
*/
try {
src.close() ;
} catch (IOException ex) {
System.out.println(
"Exception while closing file \"" + fileName + "\".") ;
System.out.println("Exception: " + ex) ;
System.exit(3) ;
}
return ;
}
}
和
import java.io.FileReader ;
import java.io.IOException ;
import java.util.ArrayDeque ;
/**
Skeleton for the MatchBrackets class.
*/
public class MatchBrackets {
/**
* Make a constant so it's clear we're recognising end-of-file.
*/
private final int EOF = -1 ;
/**
* A helper method to encapsulate the activity of reading a
* character.
*
* The FileReader class uses a common convention in character i/o:
* return each character as an int; this allows the value -1 to be
* used to indicate EOF. This little helper routine simply hides the
* try/catch statement that's required to handle the possibility
* that FileReader.read might throw an IOException.
*
* @param source
* source of characters
* @return EOF on end-of-file or exception, or a single character
* (as an int)
*/
private int getOneChar (FileReader source)
{
int charAsInt = EOF ;
try {
charAsInt = source.read() ;
} catch (IOException ex) {
System.out.println("Exception: " + ex) ;
charAsInt = EOF ;
}
return (charAsInt) ;
}
/**
* Recursive method to match brackets.
*
* @param src
* source of characters
*/
public void recursiveMatch (FileReader src)
throws MatchFail
{
/*
You must write a proper body for recursiveMatch. The bit of code below
is just to show you how to use getOneChar and throw an exception.
*/
int charAsInt = getOneChar(src) ;
if (charAsInt != EOF) {
char firstChar = (char) charAsInt ;
System.out.println(
"The first character of the file is '" + firstChar + "'.") ;
} else {
System.out.println("This file is empty!") ;
}
throw new MatchFail("You must write recursiveMatch!",42,
Character.toString('}'),42) ;
}
/**
* Iterative method to match brackets.
*
* @param src
* source of characters
*/
public void iterativeMatch (FileReader src) throws MatchFail
{
/*
You must write a proper body for this method, too.
*/
throw new MatchFail() ;
}
}
和
/**
Exception class for use by the bracket matching methods.
<p>
When a bracket mismatch is detected, this exception object should be
created, loaded with information about the mismatched pair of brackets, and
thrown.
</p><p>
The information provided should include the opening bracket and its index in
the file, and the closing bracket and its index in the file.
For a file containing K characters, character indices range from 0 to K-1.
By definition,
<ul>
<li> the `character' before the start of the file has index -1 and is
represented by the string "STX" (start of text).</li>
<li> the `character' after the end of the file has index K and is
represented by the string "EOF" (end of file).</li>
</ul>
</p><p>
MatchFail is subclassed from Exception, hence it is a checkable exception
and methods that might throw MatchFail must declare the exception with a
throws clause.
*/
public class MatchFail extends Exception
{
/**
Index of opening bracket of the mismatched pair.
*/
private int openNdx ;
/**
String representation of the opening bracket of the mismatched
pair.
*/
private String openBkt ;
/**
Index of closing bracket of the mismatched pair.
*/
private int closeNdx ;
/**
String representation of the opening bracket of the mismatched
pair.
*/
private String closeBkt ;
/**
Convenience constructor to set all attributes.
*/
public MatchFail (String openBkt, int openNdx,
String closeBkt, int closeNdx)
{ this.openBkt = openBkt ;
this.openNdx = openNdx ;
this.closeBkt = closeBkt ;
this.closeNdx = closeNdx ;
}
/**
Constructor.
<p>
Initialise the attributes to values that are obviously invalid so it's
easy to detect algorithm errors.
</p>
*/
public MatchFail ()
{
this("invalid",-10,"invalid",-10) ;
}
/** Retrieve the opening bracket. */
public String getOpenBkt () { return (openBkt) ; }
/** Retrieve the index of the opening bracket. */
public int getOpenIndex () { return (openNdx) ; }
/** Retrieve the closing bracket. */
public String getCloseBkt () { return (closeBkt) ; }
/** Retrieve the index of the opening bracket. */
public int getCloseIndex () { return (closeNdx) ; }
/** Set the opening bracket. */
public void setOpenBkt (String openBkt) { this.openBkt = openBkt ; }
/** Set the index of the opening bracket. */
public void setOpenIndex (int openNdx) { this.openNdx = openNdx ; }
/** Set the closing bracket. */
public void setCloseBkt (String closeBkt) { this.closeBkt = closeBkt ; }
/** Set the index of the closing bracket. */
public void setCloseIndex (int closeNdx) { this.closeNdx = closeNdx ; }
/** Return a string representation of the exception. */
public String toString ()
{
String rep = "'"+openBkt+"' at index "+openNdx+" matched to '" +
closeBkt+"' at index "+closeNdx ;
return (rep) ;
}
}
我遇到的问题是创建递归和迭代器方法以查找括号并报告缺少括号所在的索引。我真的不明白我应该怎么做。任何帮助将不胜感激!谢谢你。