1.
1 package algorithms.util; 2 3 /****************************************************************************** 4 * Compilation: javac In.java 5 * Execution: java In (basic test --- see source for required files) 6 * Dependencies: none 7 * 8 * Reads in data of various types from standard input, files, and URLs. 9 * 10 ******************************************************************************/ 11 12 import java.io.BufferedInputStream; 13 import java.io.File; 14 import java.io.IOException; 15 import java.io.InputStream; 16 import java.net.URL; 17 import java.net.Socket; 18 // import java.net.HttpURLConnection; 19 import java.net.URLConnection; 20 import java.util.ArrayList; 21 import java.util.InputMismatchException; 22 import java.util.Locale; 23 import java.util.NoSuchElementException; 24 import java.util.Scanner; 25 import java.util.regex.Pattern; 26 27 /** 28 * <i>Input</i>. This class provides methods for reading strings 29 * and numbers from standard input, file input, URLs, and sockets. 30 * <p> 31 * The Locale used is: language = English, country = US. This is consistent 32 * with the formatting conventions with Java floating-point literals, 33 * command-line arguments (via {@link Double#parseDouble(String)}) 34 * and standard output. 35 * <p> 36 * For additional documentation, see 37 * <a href="http://introcs.cs.princeton.edu/31datatype">Section 3.1</a> of 38 * <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> 39 * by Robert Sedgewick and Kevin Wayne. 40 * <p> 41 * Like {@link Scanner}, reading a token also consumes preceding Java 42 * whitespace, reading a full line consumes 43 * the following end-of-line delimeter, while reading a character consumes 44 * nothing extra. 45 * <p> 46 * Whitespace is defined in {@link Character#isWhitespace(char)}. Newlines 47 * consist of , , , and Unicode hex code points 0x2028, 0x2029, 0x0085; 48 * see <tt><a href="http://www.docjar.com/html/api/java/util/Scanner.java.html"> 49 * Scanner.java</a></tt> (NB: Java 6u23 and earlier uses only , , ). 50 * 51 * @author David Pritchard 52 * @author Robert Sedgewick 53 * @author Kevin Wayne 54 */ 55 public final class In { 56 57 ///// begin: section (1 of 2) of code duplicated from In to StdIn. 58 59 // assume Unicode UTF-8 encoding 60 private static final String CHARSET_NAME = "UTF-8"; 61 62 // assume language = English, country = US for consistency with System.out. 63 private static final Locale LOCALE = Locale.US; 64 65 // the default token separator; we maintain the invariant that this value 66 // is held by the scanner's delimiter between calls 67 private static final Pattern WHITESPACE_PATTERN 68 = Pattern.compile("\p{javaWhitespace}+"); 69 70 // makes whitespace characters significant 71 private static final Pattern EMPTY_PATTERN 72 = Pattern.compile(""); 73 74 // used to read the entire input. source: 75 // http://weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html 76 private static final Pattern EVERYTHING_PATTERN 77 = Pattern.compile("\A"); 78 79 //// end: section (1 of 2) of code duplicated from In to StdIn. 80 81 private Scanner scanner; 82 83 /** 84 * Initializes an input stream from standard input. 85 */ 86 public In() { 87 scanner = new Scanner(new BufferedInputStream(System.in), CHARSET_NAME); 88 scanner.useLocale(LOCALE); 89 } 90 91 /** 92 * Initializes an input stream from a socket. 93 * 94 * @param socket the socket 95 * @throws IllegalArgumentException if cannot open {@code socket} 96 * @throws NullPointerException if {@code socket} is {@code null} 97 */ 98 public In(Socket socket) { 99 if (socket == null) throw new NullPointerException("argument is null"); 100 try { 101 InputStream is = socket.getInputStream(); 102 scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); 103 scanner.useLocale(LOCALE); 104 } 105 catch (IOException ioe) { 106 throw new IllegalArgumentException("Could not open " + socket); 107 } 108 } 109 110 /** 111 * Initializes an input stream from a URL. 112 * 113 * @param url the URL 114 * @throws IllegalArgumentException if cannot open {@code url} 115 * @throws NullPointerException if {@code url} is {@code null} 116 */ 117 public In(URL url) { 118 if (url == null) throw new NullPointerException("argument is null"); 119 try { 120 URLConnection site = url.openConnection(); 121 InputStream is = site.getInputStream(); 122 scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); 123 scanner.useLocale(LOCALE); 124 } 125 catch (IOException ioe) { 126 throw new IllegalArgumentException("Could not open " + url); 127 } 128 } 129 130 /** 131 * Initializes an input stream from a file. 132 * 133 * @param file the file 134 * @throws IllegalArgumentException if cannot open {@code file} 135 * @throws NullPointerException if {@code file} is {@code null} 136 */ 137 public In(File file) { 138 if (file == null) throw new NullPointerException("argument is null"); 139 try { 140 scanner = new Scanner(file, CHARSET_NAME); 141 scanner.useLocale(LOCALE); 142 } 143 catch (IOException ioe) { 144 throw new IllegalArgumentException("Could not open " + file); 145 } 146 } 147 148 149 /** 150 * Initializes an input stream from a filename or web page name. 151 * 152 * @param name the filename or web page name 153 * @throws IllegalArgumentException if cannot open {@code name} as 154 * a file or URL 155 * @throws NullPointerException if {@code name} is {@code null} 156 */ 157 public In(String name) { 158 if (name == null) throw new NullPointerException("argument is null"); 159 try { 160 // first try to read file from local file system 161 File file = new File(name); 162 if (file.exists()) { 163 scanner = new Scanner(file, CHARSET_NAME); 164 scanner.useLocale(LOCALE); 165 return; 166 } 167 168 // next try for files included in jar 169 URL url = getClass().getResource(name); 170 171 // or URL from web 172 if (url == null) { 173 url = new URL(name); 174 } 175 176 URLConnection site = url.openConnection(); 177 178 // in order to set User-Agent, replace above line with these two 179 // HttpURLConnection site = (HttpURLConnection) url.openConnection(); 180 // site.addRequestProperty("User-Agent", "Mozilla/4.76"); 181 182 InputStream is = site.getInputStream(); 183 scanner = new Scanner(new BufferedInputStream(is), CHARSET_NAME); 184 scanner.useLocale(LOCALE); 185 } 186 catch (IOException ioe) { 187 throw new IllegalArgumentException("Could not open " + name); 188 } 189 } 190 191 /** 192 * Initializes an input stream from a given {@link Scanner} source; use with 193 * <tt>new Scanner(String)</tt> to read from a string. 194 * <p> 195 * Note that this does not create a defensive copy, so the 196 * scanner will be mutated as you read on. 197 * 198 * @param scanner the scanner 199 * @throws NullPointerException if {@code scanner} is {@code null} 200 */ 201 public In(Scanner scanner) { 202 if (scanner == null) throw new NullPointerException("argument is null"); 203 this.scanner = scanner; 204 } 205 206 /** 207 * Returns true if this input stream exists. 208 * 209 * @return <tt>true</tt> if this input stream exists; <tt>false</tt> otherwise 210 */ 211 public boolean exists() { 212 return scanner != null; 213 } 214 215 //// begin: section (2 of 2) of code duplicated from In to StdIn, 216 //// with all methods changed from "public" to "public static". 217 218 /** 219 * Returns true if input stream is empty (except possibly whitespace). 220 * Use this to know whether the next call to {@link #readString()}, 221 * {@link #readDouble()}, etc will succeed. 222 * 223 * @return <tt>true</tt> if this input stream is empty (except possibly whitespace); 224 * <tt>false</tt> otherwise 225 */ 226 public boolean isEmpty() { 227 return !scanner.hasNext(); 228 } 229 230 /** 231 * Returns true if this input stream has a next line. 232 * Use this method to know whether the 233 * next call to {@link #readLine()} will succeed. 234 * This method is functionally equivalent to {@link #hasNextChar()}. 235 * 236 * @return <tt>true</tt> if this input stream is empty; 237 * <tt>false</tt> otherwise 238 */ 239 public boolean hasNextLine() { 240 return scanner.hasNextLine(); 241 } 242 243 /** 244 * Returns true if this input stream has more inputy (including whitespace). 245 * Use this method to know whether the next call to {@link #readChar()} will succeed. 246 * This method is functionally equivalent to {@link #hasNextLine()}. 247 * 248 * @return <tt>true</tt> if this input stream has more input (including whitespace); 249 * <tt>false</tt> otherwise 250 */ 251 public boolean hasNextChar() { 252 scanner.useDelimiter(EMPTY_PATTERN); 253 boolean result = scanner.hasNext(); 254 scanner.useDelimiter(WHITESPACE_PATTERN); 255 return result; 256 } 257 258 259 /** 260 * Reads and returns the next line in this input stream. 261 * 262 * @return the next line in this input stream; <tt>null</tt> if no such line 263 */ 264 public String readLine() { 265 String line; 266 try { 267 line = scanner.nextLine(); 268 } 269 catch (NoSuchElementException e) { 270 line = null; 271 } 272 return line; 273 } 274 275 /** 276 * Reads and returns the next character in this input stream. 277 * 278 * @return the next character in this input stream 279 */ 280 public char readChar() { 281 scanner.useDelimiter(EMPTY_PATTERN); 282 String ch = scanner.next(); 283 assert ch.length() == 1 : "Internal (Std)In.readChar() error!" 284 + " Please contact the authors."; 285 scanner.useDelimiter(WHITESPACE_PATTERN); 286 return ch.charAt(0); 287 } 288 289 290 /** 291 * Reads and returns the remainder of this input stream, as a string. 292 * 293 * @return the remainder of this input stream, as a string 294 */ 295 public String readAll() { 296 if (!scanner.hasNextLine()) 297 return ""; 298 299 String result = scanner.useDelimiter(EVERYTHING_PATTERN).next(); 300 // not that important to reset delimeter, since now scanner is empty 301 scanner.useDelimiter(WHITESPACE_PATTERN); // but let's do it anyway 302 return result; 303 } 304 305 306 /** 307 * Reads the next token from this input stream and returns it as a <tt>String</tt>. 308 * 309 * @return the next <tt>String</tt> in this input stream 310 */ 311 public String readString() { 312 return scanner.next(); 313 } 314 315 /** 316 * Reads the next token from this input stream, parses it as a <tt>int</tt>, 317 * and returns the <tt>int</tt>. 318 * 319 * @return the next <tt>int</tt> in this input stream 320 */ 321 public int readInt() { 322 return scanner.nextInt(); 323 } 324 325 /** 326 * Reads the next token from this input stream, parses it as a <tt>double</tt>, 327 * and returns the <tt>double</tt>. 328 * 329 * @return the next <tt>double</tt> in this input stream 330 */ 331 public double readDouble() { 332 return scanner.nextDouble(); 333 } 334 335 /** 336 * Reads the next token from this input stream, parses it as a <tt>float</tt>, 337 * and returns the <tt>float</tt>. 338 * 339 * @return the next <tt>float</tt> in this input stream 340 */ 341 public float readFloat() { 342 return scanner.nextFloat(); 343 } 344 345 /** 346 * Reads the next token from this input stream, parses it as a <tt>long</tt>, 347 * and returns the <tt>long</tt>. 348 * 349 * @return the next <tt>long</tt> in this input stream 350 */ 351 public long readLong() { 352 return scanner.nextLong(); 353 } 354 355 /** 356 * Reads the next token from this input stream, parses it as a <tt>short</tt>, 357 * and returns the <tt>short</tt>. 358 * 359 * @return the next <tt>short</tt> in this input stream 360 */ 361 public short readShort() { 362 return scanner.nextShort(); 363 } 364 365 /** 366 * Reads the next token from this input stream, parses it as a <tt>byte</tt>, 367 * and returns the <tt>byte</tt>. 368 * <p> 369 * To read binary data, use {@link BinaryIn}. 370 * 371 * @return the next <tt>byte</tt> in this input stream 372 */ 373 public byte readByte() { 374 return scanner.nextByte(); 375 } 376 377 /** 378 * Reads the next token from this input stream, parses it as a <tt>boolean</tt> 379 * (interpreting either <tt>"true"</tt> or <tt>"1"</tt> as <tt>true</tt>, 380 * and either <tt>"false"</tt> or <tt>"0"</tt> as <tt>false</tt>). 381 * 382 * @return the next <tt>boolean</tt> in this input stream 383 */ 384 public boolean readBoolean() { 385 String s = readString(); 386 if (s.equalsIgnoreCase("true")) return true; 387 if (s.equalsIgnoreCase("false")) return false; 388 if (s.equals("1")) return true; 389 if (s.equals("0")) return false; 390 throw new InputMismatchException(); 391 } 392 393 /** 394 * Reads all remaining tokens from this input stream and returns them as 395 * an array of strings. 396 * 397 * @return all remaining tokens in this input stream, as an array of strings 398 */ 399 public String[] readAllStrings() { 400 // we could use readAll.trim().split(), but that's not consistent 401 // since trim() uses characters 0x00..0x20 as whitespace 402 String[] tokens = WHITESPACE_PATTERN.split(readAll()); 403 if (tokens.length == 0 || tokens[0].length() > 0) 404 return tokens; 405 String[] decapitokens = new String[tokens.length-1]; 406 for (int i = 0; i < tokens.length-1; i++) 407 decapitokens[i] = tokens[i+1]; 408 return decapitokens; 409 } 410 411 /** 412 * Reads all remaining lines from this input stream and returns them as 413 * an array of strings. 414 * 415 * @return all remaining lines in this input stream, as an array of strings 416 */ 417 public String[] readAllLines() { 418 ArrayList<String> lines = new ArrayList<String>(); 419 while (hasNextLine()) { 420 lines.add(readLine()); 421 } 422 return lines.toArray(new String[0]); 423 } 424 425 426 /** 427 * Reads all remaining tokens from this input stream, parses them as integers, 428 * and returns them as an array of integers. 429 * 430 * @return all remaining lines in this input stream, as an array of integers 431 */ 432 public int[] readAllInts() { 433 String[] fields = readAllStrings(); 434 int[] vals = new int[fields.length]; 435 for (int i = 0; i < fields.length; i++) 436 vals[i] = Integer.parseInt(fields[i]); 437 return vals; 438 } 439 440 /** 441 * Reads all remaining tokens from this input stream, parses them as doubles, 442 * and returns them as an array of doubles. 443 * 444 * @return all remaining lines in this input stream, as an array of doubles 445 */ 446 public double[] readAllDoubles() { 447 String[] fields = readAllStrings(); 448 double[] vals = new double[fields.length]; 449 for (int i = 0; i < fields.length; i++) 450 vals[i] = Double.parseDouble(fields[i]); 451 return vals; 452 } 453 454 ///// end: section (2 of 2) of code duplicated from In to StdIn */ 455 456 /** 457 * Closes this input stream. 458 */ 459 public void close() { 460 scanner.close(); 461 } 462 463 /** 464 * Reads all integers from a file and returns them as 465 * an array of integers. 466 * 467 * @param filename the name of the file 468 * @return the integers in the file 469 * @deprecated Replaced by <tt>new In(filename)</tt>.{@link #readAllInts()}. 470 */ 471 public static int[] readInts(String filename) { 472 return new In(filename).readAllInts(); 473 } 474 475 /** 476 * Reads all doubles from a file and returns them as 477 * an array of doubles. 478 * 479 * @param filename the name of the file 480 * @return the doubles in the file 481 * @deprecated Replaced by <tt>new In(filename)</tt>.{@link #readAllDoubles()}. 482 */ 483 public static double[] readDoubles(String filename) { 484 return new In(filename).readAllDoubles(); 485 } 486 487 /** 488 * Reads all strings from a file and returns them as 489 * an array of strings. 490 * 491 * @param filename the name of the file 492 * @return the strings in the file 493 * @deprecated Replaced by <tt>new In(filename)</tt>.{@link #readAllStrings()}. 494 */ 495 public static String[] readStrings(String filename) { 496 return new In(filename).readAllStrings(); 497 } 498 499 /** 500 * Reads all integers from standard input and returns them 501 * an array of integers. 502 * 503 * @return the integers on standard input 504 * @deprecated Replaced by {@link StdIn#readAllInts()}. 505 */ 506 public static int[] readInts() { 507 return new In().readAllInts(); 508 } 509 510 /** 511 * Reads all doubles from standard input and returns them as 512 * an array of doubles. 513 * 514 * @return the doubles on standard input 515 * @deprecated Replaced by {@link StdIn#readAllDoubles()}. 516 */ 517 public static double[] readDoubles() { 518 return new In().readAllDoubles(); 519 } 520 521 /** 522 * Reads all strings from standard input and returns them as 523 * an array of strings. 524 * 525 * @return the strings on standard input 526 * @deprecated Replaced by {@link StdIn#readAllStrings()}. 527 */ 528 public static String[] readStrings() { 529 return new In().readAllStrings(); 530 } 531 532 /** 533 * Unit tests the <tt>In</tt> data type. 534 */ 535 public static void main(String[] args) { 536 In in; 537 String urlName = "http://introcs.cs.princeton.edu/stdlib/InTest.txt"; 538 539 // read from a URL 540 System.out.println("readAll() from URL " + urlName); 541 System.out.println("---------------------------------------------------------------------------"); 542 try { 543 in = new In(urlName); 544 System.out.println(in.readAll()); 545 } 546 catch (Exception e) { 547 System.out.println(e); 548 } 549 System.out.println(); 550 551 // read one line at a time from URL 552 System.out.println("readLine() from URL " + urlName); 553 System.out.println("---------------------------------------------------------------------------"); 554 try { 555 in = new In(urlName); 556 while (!in.isEmpty()) { 557 String s = in.readLine(); 558 System.out.println(s); 559 } 560 } 561 catch (Exception e) { 562 System.out.println(e); 563 } 564 System.out.println(); 565 566 // read one string at a time from URL 567 System.out.println("readString() from URL " + urlName); 568 System.out.println("---------------------------------------------------------------------------"); 569 try { 570 in = new In(urlName); 571 while (!in.isEmpty()) { 572 String s = in.readString(); 573 System.out.println(s); 574 } 575 } 576 catch (Exception e) { 577 System.out.println(e); 578 } 579 System.out.println(); 580 581 582 // read one line at a time from file in current directory 583 System.out.println("readLine() from current directory"); 584 System.out.println("---------------------------------------------------------------------------"); 585 try { 586 in = new In("./InTest.txt"); 587 while (!in.isEmpty()) { 588 String s = in.readLine(); 589 System.out.println(s); 590 } 591 } 592 catch (Exception e) { 593 System.out.println(e); 594 } 595 System.out.println(); 596 597 598 // read one line at a time from file using relative path 599 System.out.println("readLine() from relative path"); 600 System.out.println("---------------------------------------------------------------------------"); 601 try { 602 in = new In("../stdlib/InTest.txt"); 603 while (!in.isEmpty()) { 604 String s = in.readLine(); 605 System.out.println(s); 606 } 607 } 608 catch (Exception e) { 609 System.out.println(e); 610 } 611 System.out.println(); 612 613 // read one char at a time 614 System.out.println("readChar() from file"); 615 System.out.println("---------------------------------------------------------------------------"); 616 try { 617 in = new In("InTest.txt"); 618 while (!in.isEmpty()) { 619 char c = in.readChar(); 620 System.out.print(c); 621 } 622 } 623 catch (Exception e) { 624 System.out.println(e); 625 } 626 System.out.println(); 627 System.out.println(); 628 629 // read one line at a time from absolute OS X / Linux path 630 System.out.println("readLine() from absolute OS X / Linux path"); 631 System.out.println("---------------------------------------------------------------------------"); 632 in = new In("/n/fs/introcs/www/java/stdlib/InTest.txt"); 633 try { 634 while (!in.isEmpty()) { 635 String s = in.readLine(); 636 System.out.println(s); 637 } 638 } 639 catch (Exception e) { 640 System.out.println(e); 641 } 642 System.out.println(); 643 644 645 // read one line at a time from absolute Windows path 646 System.out.println("readLine() from absolute Windows path"); 647 System.out.println("---------------------------------------------------------------------------"); 648 try { 649 in = new In("G:\www\introcs\stdlib\InTest.txt"); 650 while (!in.isEmpty()) { 651 String s = in.readLine(); 652 System.out.println(s); 653 } 654 System.out.println(); 655 } 656 catch (Exception e) { 657 System.out.println(e); 658 } 659 System.out.println(); 660 661 } 662 663 }