Accept only letters in constructor using scanner in Java - java

I guys, i'm trying to create an interactive constructor that take name and surname of the users as input in a scanner...all works, but for design now i want to accept only letters in name and surname, i've tryed with Pattern and Matcher, but the costructor still set number as name or surname (it tell me that is an invalid input but still set it in the User)
public User(){
System.out.println("insert name and surname");
System.out.println("Name: ");
Scanner input = new Scanner(System.in);
Pattern p = Pattern.compile("a,z - A,Z");
name = input.nextLine();
Matcher m = p.matcher(name);
if(m.matches()) {
this.setName(name);
}else{
System.out.println("invalid input");
}
System.out.println("SURNAME:");
surname= input.nextLine();
this.setSurname(surname);
p.matcher(surname);
System.out.println(Welcome);
System.out.println("--------------------------");
}

There's a lot of things going on here that aren't quite right. You are on your own for the stuff other than the regex-issue but consider the other points noted below.
the constructor should not be interactive - collect inputs and pass them to the constructor
your regex pattern is wrong so it will not match the inputs you actually want
you are reading the name into the name variable and then testing it - this is why it reports bad input but still stores it
you have no error recovery for handling bad input
write methods to do thing like build a user or get user input rather than trying to do everything in one place. Limit responsibilities and it is easier to write, debug, and maintain.
Regex
As written, your pattern will probably only match itself because the pattern is not well-defined. I think what you are trying to do with your regex is "^[a-zA-Z]+$".
The ^ starts the match at the beginning of the String and the $ ends the match at the end of the String. Together it means the input must be an exact match to the pattern (i.e. no extraneous characters).
The [a-zA-Z] defines a character class of alphabet characters.
The + indicates one or more characters of the preceding character class match.
Note that String has a convenience method for pattern-matching so you can do something like
String regex = "^[a-zA-Z]+$";
String input = ...
if (input.matches(regex)) { ...
Regarding how to create an instance of the User. Write methods to do things and let the constructor simply construct the object.
// Constructor is simple - just assign parameter arguments to members
public User(String name, String surname) {
this.name = name;
this.surname = surname;
}
// a method for constructing a User - get the user input and invoke constructor
public User buildUser(Scanner in) {
// define the regex in a constant so its not repeated
String name = promptForString("Enter name", NAME_REGEX, in);
String surname = promptForString("Enter surname", in);
return new User(name, surname);
}
// get the input, check against regex, return it if valid
public String promptForString(String prompt, String regex, Scanner in) {
for (;;) {
String input = in.readLine();
if (!input.matches(regex)) {
System.out.println("Invalid input - try again");
continue;
}
return input;
}
}

First I'd say such complex logic shouldn't be used in a constructor. Use it in our main method or any other dedicated method and construct the object from the processed results:
...
Scanner scanner = new Scanner(System.in);
Pattern p = Pattern.compile(???);
User user = new User();
String name = scanner.nextLine().trim()
if( p.matcher(name).matches() )
{
user.setName(name);
}
...
Now let's talk about why you code is probably not working correctly and that's because of Regex. The regex expression you use maybe does not what you think. With external third-party tools like Regexr you can see what your expressions do.
In your case you only want to allow character but not numbers. This can be done with the Regex [A-Za-z] Now we'd check if the string is a single letter... However names rarely consist of a single character so we've to add a quantifier operator to the regex. Now let's assume a name can range between 0 and infinite letters. In such a case the correct quantifier would be + (at least 1) which leads to our final result: Pattern p = Pattern.compile("[A-Za-z]+")
Code I used for testing:
String val = "";
Pattern pattern = Pattern.compile( "^[A-Za-z]+$" );
try ( Scanner scanner = new Scanner( System.in ) )
{
String input = scanner.nextLine().trim();
Matcher m = pattern.matcher( input );
if(m.matches())
val = input;
}
System.out.println("Value: " + val);

Related

Calling on a Method to Display Output Names from Chat Log

I'm having trouble with implementing a method into a bit of code for an output. Essentially, I created a method called getName which assigns a persons name to a unique number. Then, I get an input file containing chat logs. After I filter out the lines I need, I need it to be able to display the person's name instead of the number. Here is a snippet of my method:
public static String getName(int id) {
// External identifiers specified
switch (id) {
case 5644:
return "Steve Jobs";
case 5640:
return "John Smith";
case 5663:
return "Johnny Appleseed";
And here is the code that takes my input, and displays the output I need:
try
{
// assigns the input file to a filereader object
BufferedReader infile = new BufferedReader(new FileReader(log));
sc = new Scanner(log);
while(sc.hasNext())
{
String line=sc.nextLine();
if(line.contains("LANTALK")){
Pattern pattern = Pattern.compile("
(\\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s\\[D\\].+<MBXID>(\\d+)
<\\/MBXID><MBXTO>(\\d+)<\\/MBXTO>.+<MSGTEXT>(.+)
<\\/MSGTEXT>", Pattern.MULTILINE + Pattern.DOTALL);
// Multiline is used to capture the LANMSG more than
once, and Dotall is used to make the '.' term in regex
also match the newline in the input
Matcher matcher = pattern.matcher(line);
while (matcher.find())
{
String output = matcher.group(1) + " [" +
matcher.group(2) + "] to [" + matcher.group(3) + "] "
+ matcher.group(4);
System.out.println(output);
System.out.println();
}
} // End of if
} // End of while
Each line of output looks like this:
14:49:28.817 [1095] to [5607] I could poke around with it a bit and see what's available.
I just need the numbers 1095 and 5607 to display the person's name that I've specified in my method. So I'm asking how I implement that into my code? Is there a special way that I need to call upon the method in order for it to recognize the numbers? Do I use some sort of regular expression or XML? Thanks for the help!
You should be using a Dictionary
Benefits of using a dictionary:
You would be able to access both the user's names and their ID numbers as key-value pairs.
They are fast.
You would eliminate the need for switch statements to keep track of user's IDs.
Links:
Associative Array (another name for dictionary)
Dictionaries, Hash-Tables and Sets
Java Dictionary example

Using Scanner to find letter

What I'm trying to do here is have a user input a sentence or some type of string, then have the scanner search through the string to determine if there is an "e" or "E" in there. If the scanner finds either one of those it will replace them with "xyz." If they are not present then it should return "All is good!" The code I have thus far is:
public class Example {
String userInput;
Scanner in = new Scanner(System.in);
System.out.println("Please write a sentence.");
userInput = in.nextLine();
System.out.println(userInput.replace("e","xyz"));
System.out.println(userInput.replace("E","xyz"));
in.close();
}
As I think you can tell this really just prints the same line twice, once removing a lower case e and the other removing a capital E. I was looking for a way to combine the two replacements and then have it replace and print if it finds an e or just print "All is good!" if there are no "e"s.
This isn't related to Scanner at all really. Trivial approach:
String replaced = userInput.replace("e","xyz").replace("E","xyz");
String out = replaced.equals(userInput) ? "All is good!" : replaced;
System.out.println(out);
Or use replaceAll:
Pattern eE = Pattern.compile("[eE]");
String replaced = eE.matcher(userInput).replaceAll("xyz");
You're going to want to look into Pattern and its associate Matcher. This can give you precisely what you want.
While String#replaceAll gives you what you want, it's not entirely semantic; you can certainly replace all of the "e"s with "xyz" and then compare them to see if there was no change, but using Matcher gives you a bit more obvious control over the logic.
We first need to compile a regex, then build a matcher from the compiled regex. If we find a match, we can then replace the strings; otherwise, we can print out our value.
String userInput;
Scanner in = new Scanner(System.in);
System.out.println("Please write a sentence.");
userInput = in.nextLine();
Pattern pattern = Pattern.compile("[eE]");
Matcher matcher = pattern.matcher(userInput);
if(matcher.find()) {
System.out.println(matcher.replaceAll("xyz"));
} else {
System.out.println("All is good!");
}
System.out.println(userInput.replaceAll("[eE]","xyz"));
Also, don't close the System.in stream. It's not desirable to close that out in case some other part of your application wants to make use of it, or if you want to make use of it later.
Java strings are immutable, so you can't just call replace on userInput and expect it to be modified in place. You need to save the result of the function call.

How to get the string between double quotes in a string in Java [duplicate]

This question already has answers here:
Split string on spaces in Java, except if between quotes (i.e. treat \"hello world\" as one token) [duplicate]
(1 answer)
Java Regex for matching quoted string with escaped quotes
(1 answer)
Closed 8 years ago.
For example, input will be like:
AddItem rt456 4 12 BOOK “File Structures” “Addison-Wesley” “Michael Folk”
and I want to read all by using scanner and put it in a array.
like:
info[0] = rt456
info[1] = 4
..
..
info[4] = File Structures
info[5] = Addison-Wesley
So how can I get the string between quotes?
EDIT: a part of my code->
public static void main(String[] args) {
String command;
String[] line = new String[6];
Scanner read = new Scanner(System.in);
Library library = new Library();
command = read.next();
if(command.matches("AddItem"))
{
line[0] = read.next(); // Serial Number
line[1] = read.next(); // Shelf Number
line[2] = read.next(); // Shelf Index
command = read.next(); // Type of the item. "Book" - "CD" - "Magazine"
if(command.matches("BOOK"))
{
line[3] = read.next(); // Name
line[4] = read.next(); // Publisher
line[5] = read.next(); // Author
Book yeni = new Book(line[0],Integer.parseInt(line[1]),Integer.parseInt(line[2]),line[3],line[4],line[5]);
}
}
}
so I use read.next to read String without quotes.
SOLVED BY USING REGEX AS
read.next("([^\"]\\S*|\".+?\")\\s*");
You can use StreamTokenizer for this in a pinch. If operating on a String, wrap it with a StringReader. If operating on a file just pass your Reader to it.
// Replace “ and ” with " to make parsing easier; do this only if you truly are
// using pretty quotes (as you are in your post).
inputString = inputString.replaceAll("[“”]", "\"");
StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(inputString));
tokenizer.resetSyntax();
tokenizer.whitespaceChars(0, 32);
tokenizer.wordChars(33, 255);
tokenizer.quoteChar('\"');
while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
// tokenizer.sval will contain the token
System.out.println(tokenizer.sval);
}
You will have to use an appropriate configuration for non-ASCII text, the above is just an example.
If you want to pull numbers out separately, then the default StreamTokenizer configuration is fine, although it uses double and provides no int numeric tokens. Annoyingly, it is not possible to simply disable number parsing without resetting the syntax from scratch.
If you don't want to mess with all this, you could also consider changing the input format to something more convenient, as in Steve Sarcinella's good suggestion, if it is appropriate.
As a reference, take a look at this: Scanner Docs
How you read from the scanner is determined by how you will present the data to your user.
If they are typing it all on one line:
Scanner scanner = new Scanner(System.in);
String result = "";
System.out.println("Enter Data:");
result = scanner.nextLine();
Otherwise if you split it up into input fields you could do:
Scanner scanner = new Scanner(System.in);
System.out.println("Enter Identifier:");
info[0] = scanner.nextLine();
System.out.println("Enter Num:");
info[1] = scanner.nextLine();
...
If you want to validate anything before assigning the data to a variable, try using scanner.next(""); where the quotes contain a regex pattern to match
EDIT:
Check here for regex info.
As an example, say I have a string
String foo = "The cat in the hat";
regex (Regular Expressions) can be used to manipulate this string in a very quick and efficient manner. If I take that string and do foo = foo.replace("\\s+", "");, this will replace any whitespace with nothing, therefore eliminating whitespace.
Breaking down the argument \\s+, we have \s which means match any character that is whitespace.
The extra \ before \s is a an escape character that allows the \s to be read properly.
The + means match the previous expression 0 or more times. (Match all).
So foo, after running replace, would be "TheCatInTheHat"
Same this regex logic can apply to scanner.next(String regex);
Hopefully this helps a bit more, I'm not the best at explanation :)
An alternative using a messy regular expression:
public static void main(String[] args) throws Exception {
Pattern p = Pattern.compile("^(\\w*)[\\s]+(\\w*)[\\s]+(\\w*)[\\s]+(\\w*)[\\s]+(\\w*)[\\s]+[“](.*)[”][\\s]+[“](.*)[”][\\s]+[“](.*)[”]");
Matcher m = p.matcher("AddItem rt456 4 12 BOOK “File Structures” “Addison-Wesley” “Michael Folk”");
if (m.find()) {
for (int i=1;i<=m.groupCount();i++) {
System.out.println(m.group(i));
}
}
}
That prints:
AddItem
rt456
4
12
BOOK
File Structures
Addison-Wesley
Michael Folk
I assumed quotes are as you typed them in the question “” and not "", so they dont need to be escaped.
You can try this. I have prepared the demo for your requirement
public static void main(String args[]) {
String str = "\"ABC DEF\"";
System.out.println(str);
String str1 = str.replaceAll("\"", "");
System.out.println(str1);
}
After reading just replace the double quotes with empty string

Java regex string output not as expected

I'm trying to write some code to validate email addresses based on specific guidelines given to me, and one of the guidelines is that an address such as cath#[10.1.1] should be valid. I've gotten stuck and can't figure out what's wrong with my regex string:
"[A-Za-z0-9._%+-]+[#|_at_]+[\\[|[A-Za-z0-9-]]+[0-9\\.|_dot_]+[\\]|com|com.au|co.ca|co.nz|co.us|co.uk]{2,4}"
this is some example output:
Enter an email address
cath#[10.1.1]
cath#[10.1.1] is not a valid email address
cath#[10.1.1.a]
cath#[10.1.1.a] is a valid email address
cath#[10.1.1.]
cath#[10.1.1.] is a valid email address
The last two input/outputs should be invalid, whilst the first should be valid. Could anyone possibly point me in the right direction? Thanks
EDIT - here is my code if it helps anyone
import java.util.*;
import java.lang.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class EmailAddresses {
public static void main(String[] args) {
String line;
System.out.println("Enter an email address");
Scanner scan = new Scanner(System.in);
while (scan.hasNextLine()) {
line = scan.nextLine();
Pattern pattern = Pattern.compile("[A-Za-z0-9._%+-]+(?:#|_at_)(?:\\[|[A-Za-z0-9-])(?:0-9\\.|_dot_)(?:\\]|com|com\\.au|co\\.ca|co\\.nz|co\\.us|co\\.uk){2,4}");
Matcher mat = pattern.matcher(line);
if(mat.matches()){
line = line.toLowerCase();
System.out.println(line + " is a valid email address");
}else{
System.out.println(line + " is not a valid email address");
}
}
}
}
Here is what the regex flavor understands with the initial regex:
I think there is a misconcepttion. Brackets [] create a character class: a sequence of characters alternatives.
Here brackets are used to declare a sequence of words alternatives, that's not the intented behavior. For declaring sequence of words alternatives, use a non-capturing group (?:...) and inside this group , use the logical operator |.
For example:
"[\\[|[A-Za-z0-9-]]+" becomes "(?:\\[|[A-Za-z0-9-])+"
Try this regex instead:
^[A-Za-z0-9._%+-]+(?:#|_at_)(?:\[(?:\d|\.|_dot_)+(?<!\.)\]|[A-Za-z\d._-]+\.(?:com|com\.au|co\.ca|co\.nz|co\.us|co\.uk))$
Description
Demo
http://regex101.com/r/dS8qF4
Since you are not restricted to using a single regex, I suggest you split the check.
For instance, here is a method which will try and find the separator in your input:
private static int trySeparator(final String input, final String separator)
{
int ret = input.indexOf(separator);
if (ret == -1)
return ret;
return ret == input.lastIndexOf(separator) ? ret : -1;
}
Use that within your main validation method for # and _at_, then separate the first and second parts and check them separately. Much easier than a single regex, more testable ;)

java phone number validation

Here is my problem:
Create a constructor for a telephone number given a string in the form xxx-xxx-xxxx or xxx-xxxx for a local number. Throw an exception if the format is not valid.
So I was thinking to validate it using a regular expression, but I don't know if I'm doing it correctly. Also what kind of exception would I have to throw? Do I need to create my own exception?
public TelephoneNumber(String aString){
if(isPhoneNumberValid(aString)==true){
StringTokenizer tokens = new StringTokenizer("-");
if(tokens.countTokens()==3){
areaCode = Integer.parseInt(tokens.nextToken());
exchangeCode = Integer.parseInt(tokens.nextToken());
number = Integer.parseInt(tokens.nextToken());
}
else if(tokens.countTokens()==2){
exchangeCode = Integer.parseInt(tokens.nextToken());
number = Integer.parseInt(tokens.nextToken());
}
else{
//throw an excemption here
}
}
}
public static boolean isPhoneNumberValid(String phoneNumber){
boolean isValid = false;
//Initialize reg ex for phone number.
String expression = "(\\d{3})(\\[-])(\\d{4})$";
CharSequence inputStr = phoneNumber;
Pattern pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher(inputStr);
if(matcher.matches()){
isValid = true;
}
return isValid;
}
Hi sorry, yes this is homework. For this assignments the only valid format are xxx-xxx-xxxx and xxx-xxxx, all other formats (xxx)xxx-xxxx or xxxxxxxxxx are invalid in this case.
I would like to know if my regular expression is correct
So I was thinking to validate it using a regular expression, but I don't know if I'm doing it correctly.
It indeed looks overcomplicated. Also, matching xxx-xxx-xxxx or xxx-xxxx where x is a digit can be done better with "(\\d{3}-){1,2}\\d{4}". To learn more about regex I recommend to go through http://regular-expressions.info.
Also what kind of exception would I have to throw? Do I need to create my own exception?
A ValidatorException seems straight forward.
public static void isPhoneNumberValid(String phoneNumber) throws ValidatorException {
if (!phoneNumber.matches(regex)) {
throws ValidatorException("Invalid phone number");
}
}
If you don't want to create one yourself for some reasons, then I'd probably pick IllegalArgumentException, but still, I don't recommend that.
That said, this validation of course doesn't cover international and/or external telephone numbers. Unless this is really homework, I'd suggest to rethink the validation.
^(([(]?(\d{2,4})[)]?)|(\d{2,4})|([+1-9]+\d{1,2}))?[-\s]?(\d{2,3})?[-\s]?((\d{7,8})|(\d{3,4}[-\s]\d{3,4}))$
matches:
(0060)123-12345678, (0060)12312345678, (832)123-1234567, (006)03-12345678,
(006)03-12345678, 00603-12345678, 0060312345678
0000-123-12345678, 0000-12-12345678, 0000-1212345678 ... etc.
1234-5678, 01-123-4567
Can replace '-' with SPACE i.e (0080) 123 12345678
Also matches +82-123-1234567, +82 123 1234567, +800 01 12345678 ... etc.
More for house-hold/private number.
Not for 1-800-000-0000 type of number
*Tested with Regex tester http://regexpal.com/
You could match those patterns pretty easily as suggested by BalusC.
As a side note, StringTokenizer has been deprecated. From JavaDoc:
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
An easier way to split your string into the appropriate segments would be:
String phoneParts[] = phoneNumber.split("-");
String pincode = "589877";
Pattern pattern = Pattern.compile("\\d{6}");
\d indicates the digits. inside the braces the number of digits
Matcher matcher = pattern.matcher(pincode);
if (matcher.matches()) {
System.out.println("Pincode is Valid");
return true;
} else {
System.out.println("pincode must be a 6 digit Number");

Categories

Resources