Number.java
1 /* 2 * SPDX-FileCopyrightText: 2024 Jonas Smedegaard <dr@jones.dk 3 * 4 * SPDX-License-Identifier: GPL-3.0-or-later 5 */ 6 7 // leave parsing complexities to a common class. 8 import java.util.Scanner; 9 10 // let's complicate this task... 11 import java.util.regex.Matcher; 12 import java.util.regex.Pattern; 13 14 public class Number { 15 public static void main(String[] args) { 16 // instantiate object for scanning terminal input 17 Scanner input = new Scanner(System.in); 18 19 // precompile regex for more efficient matching 20 Pattern re_number = Pattern.compile("(-)?(\\d+)([,.](\\d+)?)*|(-)?[,.](\\d+)"); 21 // named groups would be more elegant, 22 // but supported properly only since OpenJDK 20, 23 // and java is crappy for declaring compatibility level... 24 // (note to self: yes, Perl is still relevant today!) 25 final int GRP_NEG = 1; 26 final int GRP_INT = 2; 27 final int GRP_SEP = 3; 28 final int GRP_FRAC = 4; 29 final int GRP_FRAC_ONLY_NEG = 5; 30 final int GRP_FRAC_ONLY = 6; 31 32 // define variables 33 String line; 34 float number; 35 int matches = 0; 36 37 // emit empty line before the initial query 38 System.out.println(); 39 while (true) { 40 line = requestNumber(input); 41 Matcher m = re_number.matcher(line); 42 while (m.find()) { 43 // emit empty line before each number processed 44 System.out.println(); 45 // reconstruct number from matched components 46 number = 0; 47 if (m.group(GRP_INT) != null) { 48 number += Float.parseFloat(m.group(GRP_INT)); 49 } 50 else if (m.group(GRP_FRAC_ONLY) != null) { 51 number += Float.parseFloat("." + m.group(GRP_FRAC_ONLY)); 52 } 53 if (m.group(GRP_FRAC) != null) { 54 number += Float.parseFloat("." + m.group(GRP_FRAC)); 55 } 56 if (m.group(GRP_NEG) != null || m.group(GRP_FRAC_ONLY_NEG) != null) { 57 number = -number; 58 } 59 matches++; 60 if (matches > 1) { 61 System.err.println("NOTICE: Oh, an additional number - this is real fun..."); 62 } 63 examineNumber(number); 64 } 65 if (matches <= 0) { 66 if (!stringIsFun(line)) { 67 System.err.println("ERROR: no number provided - exiting!"); 68 System.exit(0); 69 } 70 } 71 // emit empty line before next query 72 System.out.println(); 73 System.err.println("NOTICE: This is fun - let's try again..."); 74 matches = 0; 75 } 76 } 77 78 public static String requestNumber(Scanner channel) { 79 // provide a prompt 80 System.out.print("Please enter a number -> "); 81 82 // capture response as string 83 return channel.nextLine(); 84 } 85 86 public static void examineNumber(float x) { 87 if (x == (int) x) { 88 // use ternary operator for more compact code 89 System.out.printf("The number is %s.\n", ( x % 2 == 0 ) ? "even" : "uneven"); 90 } else { 91 System.out.println("The number is fractional."); 92 } 93 System.out.printf("The number is %s.\n", ( x < 0 ) ? "negative" : "positive"); 94 } 95 96 // let's add an easter egg... 97 public static boolean stringIsFun(String s) { 98 // sloppy ad-hoc regex: acceptable to be slow at getting the joke 99 if (s.matches("(?i).*\\bnumber\\b.*")) { 100 System.err.println("ERROR: Ha ha funny, but semantic (not literal) response is expected..."); 101 return true; 102 } else if (s.matches("(?i).*\\bzero|one|two|three|four|five|six|seven|eight|nine|ten|elleven|twelve|fiften|twenty|thirty|fifty|hundred.*")) { 103 System.err.println("ERROR: Ha ha clever, but digits are expected..."); 104 return true; 105 } else { 106 return false; 107 } 108 } 109 }