diff --git a/README.md b/README.md index f1ca56ee..e78baed6 100644 --- a/README.md +++ b/README.md @@ -65,13 +65,13 @@ Format: `help` #### Adding a person: `add` > Adds a person to the address book -Format: `add NAME p/PHONE_NUMBER e/EMAIL` +Format: `add NAME p/PHONE_NUMBER e/EMAIL c/POSTAL_CODE` > Words in `UPPER_CASE` are the parameters
Phone number and email can be in any order but the name must come first. Examples: -* `add John Doe p/98765432 e/johnd@gmail.com` -* `add Betsy Crowe e/bencrowe@gmail.com p/1234567 ` +* `add John Doe p/98765432 e/johnd@gmail.com c/123456` +* `add Betsy Crowe e/bencrowe@gmail.com p/1234567 c/111111` #### Listing all persons: `list` diff --git a/src/seedu/addressbook/AddressBook.java b/src/seedu/addressbook/AddressBook.java index 5a158b67..c904bdfd 100644 --- a/src/seedu/addressbook/AddressBook.java +++ b/src/seedu/addressbook/AddressBook.java @@ -65,13 +65,13 @@ public class AddressBook { * at which java String.format(...) method can insert values. * ========================================================================= */ - private static final String MESSAGE_ADDED = "New person added: %1$s, Phone: %2$s, Email: %3$s"; + private static final String MESSAGE_ADDED = "New person added: %1$s, Phone: %2$s, Email: %3$s, Postal Code: %4$s"; private static final String MESSAGE_ADDRESSBOOK_CLEARED = "Address book has been cleared!"; private static final String MESSAGE_COMMAND_HELP = "%1$s: %2$s"; private static final String MESSAGE_COMMAND_HELP_PARAMETERS = "\tParameters: %1$s"; private static final String MESSAGE_COMMAND_HELP_EXAMPLE = "\tExample: %1$s"; private static final String MESSAGE_DELETE_PERSON_SUCCESS = "Deleted Person: %1$s"; - private static final String MESSAGE_DISPLAY_PERSON_DATA = "%1$s Phone Number: %2$s Email: %3$s"; + private static final String MESSAGE_DISPLAY_PERSON_DATA = "%1$s Phone Number: %2$s Email: %3$s Postal Code: %4$s"; private static final String MESSAGE_DISPLAY_LIST_ELEMENT_INDEX = "%1$d. "; private static final String MESSAGE_GOODBYE = "Exiting Address Book... Good bye!"; private static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid command format: %1$s " + LS + "%2$s"; @@ -94,16 +94,21 @@ public class AddressBook { // These are the prefix strings to define the data type of a command parameter private static final String PERSON_DATA_PREFIX_PHONE = "p/"; private static final String PERSON_DATA_PREFIX_EMAIL = "e/"; + private static final String PERSON_DATA_PREFIX_POSTALCODE = "c/"; private static final String PERSON_STRING_REPRESENTATION = "%1$s " // name + PERSON_DATA_PREFIX_PHONE + "%2$s " // phone - + PERSON_DATA_PREFIX_EMAIL + "%3$s"; // email + + PERSON_DATA_PREFIX_EMAIL + "%3$s " // email + + PERSON_DATA_PREFIX_POSTALCODE + "%4$s"; // postal code private static final String COMMAND_ADD_WORD = "add"; private static final String COMMAND_ADD_DESC = "Adds a person to the address book."; private static final String COMMAND_ADD_PARAMETERS = "NAME " + PERSON_DATA_PREFIX_PHONE + "PHONE_NUMBER " - + PERSON_DATA_PREFIX_EMAIL + "EMAIL"; - private static final String COMMAND_ADD_EXAMPLE = COMMAND_ADD_WORD + " John Doe p/98765432 e/johnd@gmail.com"; + + PERSON_DATA_PREFIX_EMAIL + "EMAIL " + + PERSON_DATA_PREFIX_POSTALCODE + "POSTAL_CODE"; + + private static final String COMMAND_ADD_EXAMPLE = COMMAND_ADD_WORD + + " John Doe p/98765432 e/johnd@gmail.com c/123456"; private static final String COMMAND_FIND_WORD = "find"; private static final String COMMAND_FIND_DESC = "Finds all persons whose names contain any of the specified " @@ -144,11 +149,13 @@ public class AddressBook { private static final int PERSON_DATA_INDEX_NAME = 0; private static final int PERSON_DATA_INDEX_PHONE = 1; private static final int PERSON_DATA_INDEX_EMAIL = 2; + private static final int PERSON_DATA_INDEX_POSTALCODE = 3; + /** * The number of data elements for a single person. */ - private static final int PERSON_DATA_COUNT = 3; + private static final int PERSON_DATA_COUNT = 4; /** * Offset required to convert between 1-indexing and 0-indexing.COMMAND_ @@ -439,7 +446,8 @@ private static String executeAddPerson(String commandArgs) { */ private static String getMessageForSuccessfulAddPerson(String[] addedPerson) { return String.format(MESSAGE_ADDED, - getNameFromPerson(addedPerson), getPhoneFromPerson(addedPerson), getEmailFromPerson(addedPerson)); + getNameFromPerson(addedPerson), getPhoneFromPerson(addedPerson), + getEmailFromPerson(addedPerson), getPostalFromPerson(addedPerson)); } /** @@ -669,7 +677,8 @@ private static String getIndexedPersonListElementMessage(int visibleIndex, Strin */ private static String getMessageForFormattedPersonData(String[] person) { return String.format(MESSAGE_DISPLAY_PERSON_DATA, - getNameFromPerson(person), getPhoneFromPerson(person), getEmailFromPerson(person)); + getNameFromPerson(person), getPhoneFromPerson(person), + getEmailFromPerson(person), getPostalFromPerson(person)); } /** @@ -860,6 +869,15 @@ private static String getEmailFromPerson(String[] person) { return person[PERSON_DATA_INDEX_EMAIL]; } + /** + * Returns given person's postal code + * + * @param person whose postal code you want + */ + private static String getPostalFromPerson(String[] person) { + return person[PERSON_DATA_INDEX_POSTALCODE]; + } + /** * Creates a person from the given data. * @@ -868,11 +886,12 @@ private static String getEmailFromPerson(String[] person) { * @param email without data prefix * @return constructed person */ - private static String[] makePersonFromData(String name, String phone, String email) { + private static String[] makePersonFromData(String name, String phone, String email, String postalCode) { final String[] person = new String[PERSON_DATA_COUNT]; person[PERSON_DATA_INDEX_NAME] = name; person[PERSON_DATA_INDEX_PHONE] = phone; person[PERSON_DATA_INDEX_EMAIL] = email; + person[PERSON_DATA_INDEX_POSTALCODE] = postalCode; return person; } @@ -884,7 +903,8 @@ private static String[] makePersonFromData(String name, String phone, String ema */ private static String encodePersonToString(String[] person) { return String.format(PERSON_STRING_REPRESENTATION, - getNameFromPerson(person), getPhoneFromPerson(person), getEmailFromPerson(person)); + getNameFromPerson(person), getPhoneFromPerson(person), + getEmailFromPerson(person), getPostalFromPerson(person)); } /** @@ -923,7 +943,9 @@ private static Optional decodePersonFromString(String encoded) { final String[] decodedPerson = makePersonFromData( extractNameFromPersonString(encoded), extractPhoneFromPersonString(encoded), - extractEmailFromPersonString(encoded) + extractEmailFromPersonString(encoded), + extractPostalFromPersonString(encoded) + ); // check that the constructed person is valid return isPersonDataValid(decodedPerson) ? Optional.of(decodedPerson) : Optional.empty(); @@ -955,12 +977,15 @@ private static Optional> decodePersonsFromStrings(ArrayList< * @param personData person string representation */ private static boolean isPersonDataExtractableFrom(String personData) { - final String matchAnyPersonDataPrefix = PERSON_DATA_PREFIX_PHONE + '|' + PERSON_DATA_PREFIX_EMAIL; + final String matchAnyPersonDataPrefix = PERSON_DATA_PREFIX_PHONE + '|' + + PERSON_DATA_PREFIX_EMAIL+ '|' + + PERSON_DATA_PREFIX_POSTALCODE; final String[] splitArgs = personData.trim().split(matchAnyPersonDataPrefix); - return splitArgs.length == 3 // 3 arguments + return splitArgs.length == 4 // 4 arguments && !splitArgs[0].isEmpty() // non-empty arguments && !splitArgs[1].isEmpty() - && !splitArgs[2].isEmpty(); + && !splitArgs[2].isEmpty() + && !splitArgs[3].isEmpty(); } /** @@ -986,17 +1011,24 @@ private static String extractNameFromPersonString(String encoded) { private static String extractPhoneFromPersonString(String encoded) { final int indexOfPhonePrefix = encoded.indexOf(PERSON_DATA_PREFIX_PHONE); final int indexOfEmailPrefix = encoded.indexOf(PERSON_DATA_PREFIX_EMAIL); + final int indexOfPostalPrefix = encoded.indexOf(PERSON_DATA_PREFIX_POSTALCODE); // phone is last arg, target is from prefix to end of string - if (indexOfPhonePrefix > indexOfEmailPrefix) { + if (indexOfPhonePrefix > indexOfEmailPrefix && indexOfPhonePrefix > indexOfPostalPrefix) { return removePrefixSign(encoded.substring(indexOfPhonePrefix, encoded.length()).trim(), PERSON_DATA_PREFIX_PHONE); - // phone is middle arg, target is from own prefix to next prefix - } else { + // phone is before mail, target is from own prefix to next prefix + } else if ((indexOfPhonePrefix < indexOfEmailPrefix && indexOfPostalPrefix < indexOfPhonePrefix) + || (indexOfPhonePrefix < indexOfEmailPrefix && indexOfPostalPrefix > indexOfPhonePrefix)) { return removePrefixSign( encoded.substring(indexOfPhonePrefix, indexOfEmailPrefix).trim(), PERSON_DATA_PREFIX_PHONE); + // phone is before postal code, target is from own prefix to next prefix + } else { + return removePrefixSign( + encoded.substring(indexOfPhonePrefix, indexOfPostalPrefix).trim(), + PERSON_DATA_PREFIX_PHONE); } } @@ -1008,30 +1040,70 @@ private static String extractPhoneFromPersonString(String encoded) { */ private static String extractEmailFromPersonString(String encoded) { final int indexOfPhonePrefix = encoded.indexOf(PERSON_DATA_PREFIX_PHONE); + final int indexOfPostalPrefix = encoded.indexOf(PERSON_DATA_PREFIX_POSTALCODE); final int indexOfEmailPrefix = encoded.indexOf(PERSON_DATA_PREFIX_EMAIL); // email is last arg, target is from prefix to end of string - if (indexOfEmailPrefix > indexOfPhonePrefix) { + if (indexOfEmailPrefix > indexOfPhonePrefix && indexOfEmailPrefix > indexOfPostalPrefix) { return removePrefixSign(encoded.substring(indexOfEmailPrefix, encoded.length()).trim(), PERSON_DATA_PREFIX_EMAIL); - // email is middle arg, target is from own prefix to next prefix + // email is before postal code, target is from own prefix to next prefix + } else if ((indexOfEmailPrefix > indexOfPhonePrefix && indexOfEmailPrefix < indexOfPostalPrefix) + || (indexOfEmailPrefix < indexOfPhonePrefix && indexOfEmailPrefix < indexOfPostalPrefix)){ + return removePrefixSign( + encoded.substring(indexOfEmailPrefix, indexOfPostalPrefix).trim(), + PERSON_DATA_PREFIX_EMAIL); + // email is middle arg, phone is last arg, target is from own prefix to next prefix } else { return removePrefixSign( - encoded.substring(indexOfEmailPrefix, indexOfPhonePrefix).trim(), + encoded.substring(indexOfPhonePrefix, indexOfEmailPrefix).trim(), PERSON_DATA_PREFIX_EMAIL); } } + + /** + * Extracts substring representing postal code from person string representation + * + * @param encoded person string representation + * @return postal code argument WITHOUT prefix + */ + private static String extractPostalFromPersonString(String encoded) { + final int indexOfPhonePrefix = encoded.indexOf(PERSON_DATA_PREFIX_PHONE); + final int indexOfPostalPrefix = encoded.indexOf(PERSON_DATA_PREFIX_POSTALCODE); + final int indexOfEmailPrefix = encoded.indexOf(PERSON_DATA_PREFIX_EMAIL); + + // pc is last arg, target is from prefix to end of string + if (indexOfPostalPrefix > indexOfEmailPrefix && indexOfPostalPrefix > indexOfPhonePrefix) { + return removePrefixSign(encoded.substring(indexOfPostalPrefix, encoded.length()).trim(), + PERSON_DATA_PREFIX_POSTALCODE); + + // pc is before email target is from own prefix to next prefix + } else if ((indexOfPostalPrefix < indexOfEmailPrefix && indexOfPhonePrefix < indexOfPostalPrefix) + || (indexOfPostalPrefix < indexOfEmailPrefix && indexOfPhonePrefix > indexOfPostalPrefix)){ + return removePrefixSign( + encoded.substring(indexOfPostalPrefix, indexOfEmailPrefix).trim(), + PERSON_DATA_PREFIX_POSTALCODE); + + // pc is middle arg, phone is last arg, target is from own prefix to next prefix + } else { + return removePrefixSign( + encoded.substring(indexOfPostalPrefix, indexOfPhonePrefix).trim(), + PERSON_DATA_PREFIX_POSTALCODE); + } + } + /** * Returns true if the given person's data fields are valid * * @param person String array representing the person (used in internal data) */ private static boolean isPersonDataValid(String[] person) { - return isPersonNameValid(person[PERSON_DATA_INDEX_NAME]) - && isPersonPhoneValid(person[PERSON_DATA_INDEX_PHONE]) - && isPersonEmailValid(person[PERSON_DATA_INDEX_EMAIL]); + return isPersonNameValid(person[PERSON_DATA_INDEX_NAME], "(\\w|\\s)+") + && isPersonPhoneValid(person[PERSON_DATA_INDEX_PHONE], "\\d+") + && isPersonEmailValid(person[PERSON_DATA_INDEX_EMAIL], "\\S+@\\S+\\.\\S+") + && isPersonPostalValid(person[PERSON_DATA_INDEX_POSTALCODE], "\\d+"); } /* @@ -1046,9 +1118,10 @@ && isPersonPhoneValid(person[PERSON_DATA_INDEX_PHONE]) * Returns true if the given string as a legal person name * * @param name to be validated + * @param regex */ - private static boolean isPersonNameValid(String name) { - return name.matches("(\\w|\\s)+"); // name is nonempty mixture of alphabets and whitespace + private static boolean isPersonNameValid(String name, String regex) { + return isPersonPhoneValid(name, regex); // name is nonempty mixture of alphabets and whitespace //TODO: implement a more permissive validation } @@ -1056,9 +1129,10 @@ private static boolean isPersonNameValid(String name) { * Returns true if the given string as a legal person phone number * * @param phone to be validated + * @param regex */ - private static boolean isPersonPhoneValid(String phone) { - return phone.matches("\\d+"); // phone nonempty sequence of digits + private static boolean isPersonPhoneValid(String phone, String regex) { + return phone.matches(regex); // phone nonempty sequence of digits //TODO: implement a more permissive validation } @@ -1066,13 +1140,25 @@ private static boolean isPersonPhoneValid(String phone) { * Returns true if the given string is a legal person email * * @param email to be validated + * @param regex * @return whether arg is a valid person email */ - private static boolean isPersonEmailValid(String email) { - return email.matches("\\S+@\\S+\\.\\S+"); // email is [non-whitespace]@[non-whitespace].[non-whitespace] + private static boolean isPersonEmailValid(String email, String regex) { + return isPersonPhoneValid(email, regex); // email is [non-whitespace]@[non-whitespace].[non-whitespace] //TODO: implement a more permissive validation } + /** + * Returns true if the given string is a legal postal code + * + * @param postalCode to be validated + * @param regex + * @return whether arg is a legal postal code + */ + private static boolean isPersonPostalValid(String postalCode, String regex) { + return isPersonPhoneValid(postalCode, regex); // email is [non-whitespace]@[non-whitespace].[non-whitespace] + //TODO: implement a more permissive validation + } /* * =============================================== diff --git a/test/input.txt b/test/input.txt index 0b99df54..dcbb227a 100644 --- a/test/input.txt +++ b/test/input.txt @@ -19,26 +19,27 @@ # should catch invalid args format add wrong args wrong args - add Valid Name p/12345 valid@email.butNoPrefix - add Valid Name 12345 e/valid@email.butPhonePrefixMissing + add Valid Name p/12345 valid@email.butNoPrefix c/111111 + add Valid Name 12345 e/valid@email.butPhonePrefixMissing c/111111 # should catch invalid person data add []\[;] p/12345 e/valid@e.mail - add Valid Name p/not_numbers e/valid@e.mail - add Valid Name p/12345 e/notAnEmail + add Valid Name p/not_numbers e/valid@e.mail c/111111 + add Valid Name p/12345 e/notAnEmail c/111111 + add Valid Name p/12345 e/valid@e.mail c/not_numbers # should add correctly - add Adam Brown p/111111 e/adam@gmail.com + add Adam Brown p/111111 e/adam@gmail.com c/111111 list - add Betsy Choo p/222222 e/benchoo@nus.edu.sg + add Betsy Choo p/222222 e/benchoo@nus.edu.sg c/222222 list - # order of phone and email should not matter - add Charlie Dickson e/charlie.d@nus.edu.sg p/333333 + # order of phone and email and postal code should not matter + add Charlie Dickson e/charlie.d@nus.edu.sg p/333333 c/111111 list - add Dickson Ee e/dickson@nus.edu.sg p/444444 + add Dickson Ee e/dickson@nus.edu.sg p/444444 c/111111 list - add Esther Potato p/555555 e/esther@notreal.potato + add Esther Potato p/555555 c/111111 e/esther@notreal.potato list ##########################################################