All Downloads are FREE. Search and download functionalities are using the official Maven repository.

squidpony.Messaging Maven / Gradle / Ivy

Go to download

SquidLib platform-independent logic and utility code. Please refer to https://github.com/SquidPony/SquidLib .

There is a newer version: 3.0.6
Show newest version
package squidpony;

import regexodus.*;
import java.util.HashMap;

/**
 * Helps handle formation of messages from a template, using correct pronouns and helping handle various idiosyncrasies
 * in English-language text. You call the static method
 * {@link #transform(CharSequence, String, NounTrait, String, NounTrait)} (or one of its overloads) with a template that
 * has specific placeholder glyphs, along with a user name, optional target name, user NounTrait (an enum in this class)
 * to specify how the user should be addressed, including their gender, optional target NounTrait, and possibly extra
 * terms that should be inserted. The placeholder glyphs are usually followed by a specific word that is conjugated in
 * the template for the first-person case, and will be changed to fit the NounTrait for the user or target. For example,
 * you could use "@Name hit$ ^ for ~ damage!" as a message. You could transform it with user "Heero Supra", userTrait
 * NounTrait.SECOND_PERSON_SINGULAR, target "the beast", targetTrait NounTrait.UNSPECIFIED_GENDER, and extra "10" to get
 * the message "You hit the beast for 10 damage!". You could swap the user and target (along with their traits) to get
 * the message "The beast hits you for 10 damage!" You can handle more complex verbs in some cases, such as "@I hurr$$$
 * to catch up!" can be transformed to "You hurry to catch up!" or "He hurries to catch up!". The rules are fairly
 * simple; @word conjugates a specific word from a list to the correct kind for the user, while ^word does a similar
 * thing but conjugates for the target. Between 1 and 3 $ chars can be used at the end of verbs to conjugate them
 * appropriately for the present tense when the verb is performed by the user (with just $) or alternately the target
 * (if the $ chars are preceded by a ^), while @s, @ss, @sss, ^s, ^ss, or ^sss can be added at the end of nouns to
 * pluralize them if appropriate. Using one $ or s will add s or nothing, as in the case of hit becoming hits, using two
 * $ or s chars will add es or nothing, as in the case of scratch becoming scratches, and using three will add ies or y,
 * as in the case of carry becoming carries. Some unusual pluralization forms are handled; @usi will turn octop@usi into
 * octopus or octopi, and radi@usi into radius or radii, while @fves will turn el@fves into elf or elves, or dwar@fves
 * into dwarf or dwarves.
 * 
* The words you can put after a @ or ^ start with a small list and can be added to with * {@link #learnIrregularWord(String, String, String, String, String, String, String)}. The initial list is: name, * name_s, i, me, my, mine, myself, am, have, do, haven_t, don_t, or any of these with the first char capitalized (meant * for words at the start of sentences). The non-word shortened terms "m" and "ve" can be used for "I'm" and "I've", * respectively, as well as "you're" and "you've", plus "he's" for "he is" and "he's" for "he has". Most of the rest * conjugate as you would expect; @me will become him, her, it, them, you, or still more forms depending on userTrait. * You can also use @ or ^ on its own as an equivalent to @name or ^name. *
* Examples: *
* {@code Messaging.transform("@I @am @my own boss@ss.", "unused", changingTrait)} *
    *
  • When changingTrait is {@code NounTrait.FIRST_PERSON_SINGULAR}, this returns "I am my own boss."
  • *
  • When changingTrait is {@code NounTrait.FIRST_PERSON_PLURAL}, this returns "We are our own bosses."
  • *
  • When changingTrait is {@code NounTrait.SECOND_PERSON_SINGULAR}, this returns "You are your own boss."
  • *
  • When changingTrait is {@code NounTrait.SECOND_PERSON_PLURAL}, this returns "You are your own bosses."
  • *
  • When changingTrait is {@code NounTrait.NO_GENDER}, this returns "It is its own boss."
  • *
  • When changingTrait is {@code NounTrait.MALE_GENDER}, this returns "He is his own boss."
  • *
  • When changingTrait is {@code NounTrait.FEMALE_GENDER}, this returns "She is her own boss."
  • *
  • When changingTrait is {@code NounTrait.UNSPECIFIED_GENDER}, this returns "They are their own boss."
  • *
  • When changingTrait is {@code NounTrait.ADDITIONAL_GENDER}, this returns "Xe is xis own boss."
  • *
  • When changingTrait is {@code NounTrait.SPECIAL_CASE_GENDER}, this returns "Qvqe is qvqis own boss."
  • *
  • When changingTrait is {@code NounTrait.GROUP}, this returns "They are their own bosses."
  • *
* {@code Messaging.transform("@Name spit$ in ^name_s face^s!", userName, userTrait, targetName, targetTrait)} *
    *
  • When userTrait is {@code NounTrait.SECOND_PERSON_SINGULAR}, targetName is {@code "the goblin"}, and * targetTrait is {@code NounTrait.MALE_GENDER}, this returns "You spit in the goblin's face!"
  • *
  • When userName is {@code "the goblin"}, userTrait is {@code NounTrait.MALE_GENDER}, and targetTrait is * {@code NounTrait.SECOND_PERSON_SINGULAR}, this returns "The goblin spits in your face!"
  • *
  • When userTrait is {@code NounTrait.SECOND_PERSON_SINGULAR}, targetName is {@code "the goblins"}, and * targetTrait is {@code NounTrait.GROUP}, this returns "You spit in the goblins' faces!"
  • *
  • When userName is {@code "the goblins"}, userTrait is {@code NounTrait.GROUP}, and targetTrait is * {@code NounTrait.SECOND_PERSON_SINGULAR}, this returns "The goblins spit in your face!"
  • *
* Created by Tommy Ettinger on 10/31/2016. */ public class Messaging { /** * Properties of nouns needed to correctly conjugate those nouns and refer to them with pronouns, such as genders. * Includes parts of speech, which only are concerned with whether they refer to a singular noun or a plural noun, * and genders for when a gendered pronoun is needed. This provides substantial support for uncommon cases regarding * gender and pronoun preferences. That said, gender and pronoun preference can be incredibly hard to handle. * The simplest cases are for first- and second-person pronouns; here we have "I/me/my/myself" for * {@link #FIRST_PERSON_SINGULAR}, "you/you/your/yourself" for {@link #SECOND_PERSON_SINGULAR}, * "we/us/our/ourselves" for {@link #FIRST_PERSON_PLURAL}, and "you/you/your/yourselves" for * {@link #SECOND_PERSON_PLURAL}; there are more pronouns this can produce, but they aren't listed here. * Third-person pronouns are considerably more challenging because English sporadically considers gender as part of * conjugation, but doesn't provide a universally-acceptable set of gendered pronouns. *
* This at least tries to provide pronoun handling for the common cases, such as "you" not needing a gendered * pronoun at all (it uses {@link #SECOND_PERSON_SINGULAR}), and supports {@link #MALE_GENDER male}, * {@link #FEMALE_GENDER female}, {@link #NO_GENDER genderless} (using "it" and related forms; preferred especially * for things that aren't alive, and in most cases not recommended for people), * {@link #UNSPECIFIED_GENDER "unspecified"} (using "they" in place of "he" or "she"; preferred in some cases when * describing someone with a non-specific gender or an unknown gender) pronouns, and {@link #GROUP group} for when a * group of individuals, regardless of gender or genders, is referred to with a single pronoun. As mentioned, this * has support for some uncommon situations, like {@link #ADDITIONAL_GENDER additional gender} (as in, a gender that * is in addition to male and female but that is not genderless, which has a clear use case when describing * non-human species, and a more delicate use for humans who use non-binary gender pronouns; hopefully "xe" will be * acceptable), and finally a {@link #SPECIAL_CASE_GENDER "special case"} pronoun that is unpronounceable and, if * given special processing, can be used as a replacement target for customized pronouns. For the additional gender, * the non-binary gendered pronouns are modified from the male pronouns by replacing 'h' with 'x' (he becomes xe, * his becomes xis). The "special case" pronouns replace the 'h' in the male pronouns with 'qvq', except for in one * case. Where, if the female pronoun were used, it would be "hers", but the male pronoun in that case would be "his", * changing the male pronoun would lead to a difficult-to-replace case because "his" is also used in the case where * the female pronoun is the usefully distinct "her". Here, the "special case" gender diverges from what it usually * does, and uses "qvqims" in place of "his" or "hers". The "special case" pronouns should be replaced before being * displayed, since they look like gibberish or a glitch and so are probably confusing out of context. */ public enum NounTrait { /** * As in, "I am my own boss." Doesn't reference gender. */ FIRST_PERSON_SINGULAR, /** * As in, "You are your own boss." Doesn't reference gender. */ SECOND_PERSON_SINGULAR, /** * As in, "We are our own bosses." Doesn't reference gender, and applies to groups. */ FIRST_PERSON_PLURAL, /** * As in, "You are your own bosses." Doesn't reference gender, and applies to groups. */ SECOND_PERSON_PLURAL, /** * Inanimate objects or beings without gender, as in "It is its own boss." */ NO_GENDER, /** * Male pronoun preference, as in "He is his own boss." */ MALE_GENDER, /** * Female pronoun preference, as in "She is her own boss." */ FEMALE_GENDER, /** * "Singular they" pronoun preference or to be used when preference is unknown, as in "They are their own boss." */ UNSPECIFIED_GENDER, /** * Third-gender pronoun preference, potentially relevant for cultures with non-binary gender terms. As in, "Xe * is xis own boss." */ ADDITIONAL_GENDER, /** * Unpronounceable words that can be processed specially for more complex cases of pronoun preference. As in, * "Qvqe is qvqis own boss." */ SPECIAL_CASE_GENDER, /** * Any third-person plural, as in "They are their own bosses." Not to be confused with UNSPECIFIED_GENDER, which * is for singular beings, but usually uses "they" in the same way (not always). */ GROUP; public String nameText(String term) { switch (this) { case FIRST_PERSON_SINGULAR: return "I"; case FIRST_PERSON_PLURAL: return "we"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "you"; default: return term; } } public String name_sText(String term) { switch (this) { case FIRST_PERSON_SINGULAR: return "my"; case FIRST_PERSON_PLURAL: return "our"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "your"; default: if(term.isEmpty()) return ""; else if(term.endsWith("s")) return term + '\''; else return term + "'s"; } } public String iText() { switch (this) { case FIRST_PERSON_SINGULAR: return "I"; case FIRST_PERSON_PLURAL: return "we"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "you"; case NO_GENDER: return "it"; case MALE_GENDER: return "he"; case FEMALE_GENDER: return "she"; //case UNSPECIFIED_GENDER: return "they"; case ADDITIONAL_GENDER: return "xe"; case SPECIAL_CASE_GENDER: return "qvqe"; default: return "they"; } } public String meText() { switch (this) { case FIRST_PERSON_SINGULAR: return "me"; case FIRST_PERSON_PLURAL: return "us"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "you"; case NO_GENDER: return "it"; case MALE_GENDER: return "him"; case FEMALE_GENDER: return "her"; //case UNSPECIFIED_GENDER: return "them"; case ADDITIONAL_GENDER: return "xim"; case SPECIAL_CASE_GENDER: return "qvqim"; default: return "them"; } } public String myText() { switch (this) { case FIRST_PERSON_SINGULAR: return "my"; case FIRST_PERSON_PLURAL: return "our"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "your"; case NO_GENDER: return "its"; case MALE_GENDER: return "his"; case FEMALE_GENDER: return "her"; //case UNSPECIFIED_GENDER: return "their"; case ADDITIONAL_GENDER: return "xis"; case SPECIAL_CASE_GENDER: return "qvqis"; default: return "their"; } } public String mineText() { switch (this) { case FIRST_PERSON_SINGULAR: return "mine"; case FIRST_PERSON_PLURAL: return "ours"; case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: return "yours"; case NO_GENDER: return "its"; case MALE_GENDER: return "his"; case FEMALE_GENDER: return "hers"; //case UNSPECIFIED_GENDER: return "theirs"; case ADDITIONAL_GENDER: return "xis"; case SPECIAL_CASE_GENDER: return "qvqims"; default: return "theirs"; } } public String myselfText() { switch (this) { case FIRST_PERSON_SINGULAR: return "myself"; case FIRST_PERSON_PLURAL: return "ourselves"; case SECOND_PERSON_SINGULAR: return "yourself"; case SECOND_PERSON_PLURAL: return "yourselves"; case NO_GENDER: return "itself"; case MALE_GENDER: return "himself"; case FEMALE_GENDER: return "herself"; case UNSPECIFIED_GENDER: return "themself"; case ADDITIONAL_GENDER: return "ximself"; case SPECIAL_CASE_GENDER: return "qvqimself"; default: return "themselves"; } } public String sText() { switch (this) { case FIRST_PERSON_PLURAL: case SECOND_PERSON_PLURAL: case GROUP: return "s"; default: return ""; } } public String ssText() { switch (this) { case FIRST_PERSON_PLURAL: case SECOND_PERSON_PLURAL: case GROUP: return "es"; default: return ""; } } public String sssText() { switch (this) { case FIRST_PERSON_PLURAL: case SECOND_PERSON_PLURAL: case GROUP: return "ies"; default: return "y"; } } public String usiText() { switch (this) { case FIRST_PERSON_PLURAL: case SECOND_PERSON_PLURAL: case GROUP: return "i"; default: return "us"; } } public String fvesText() { switch (this) { case FIRST_PERSON_PLURAL: case SECOND_PERSON_PLURAL: case GROUP: return "ves"; default: return "f"; } } public String $Text() { switch (this) { case FIRST_PERSON_SINGULAR: case FIRST_PERSON_PLURAL: case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: case UNSPECIFIED_GENDER: case GROUP: return ""; default: return "s"; } } public String $$Text() { switch (this) { case FIRST_PERSON_SINGULAR: case FIRST_PERSON_PLURAL: case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: case UNSPECIFIED_GENDER: case GROUP: return ""; default: return "es"; } } public String $$$Text() { switch (this) { case FIRST_PERSON_SINGULAR: case FIRST_PERSON_PLURAL: case SECOND_PERSON_SINGULAR: case SECOND_PERSON_PLURAL: case UNSPECIFIED_GENDER: case GROUP: return "y"; default: return "ies"; } } public String directText(String term) { return term; } } public static class Group { public String[] members; public Group() { members = new String[]{"the goblin", "the dragon", "the warlock"}; } public Group(String... members) { this.members = members; } } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given user and their associated NounTrait. * @param message the message to transform; should contain "@" or "$" in it, at least, to be replaced * @param user the name of the user for cases where it can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, String user, NounTrait userTrait) { Replacer ur = new Replacer(userPattern, new BeingSubstitution(user, userTrait, true)); return ur.replace(message); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given group of users and that group's associated NounTrait. The NounTrait only matters * if it is first-person or second-person (in which case this uses the plural form) or if the Group contains one * member (in which case it uses any gendered pronouns specified by userTrait); it uses {@link NounTrait#GROUP} in * any other case. * @param message the message to transform; should contain "@" or "$" in it, at least, to be replaced * @param user a {@link Group} of users (a String array) for cases where it can replace text, like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, Group user, NounTrait userTrait) { Replacer ur = new Replacer(userPattern, new BeingSubstitution(userTrait, true, user.members)); return ur.replace(message); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given user, their associated NounTrait, the given target, and their NounTrait. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the name of the user for cases where it can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the name of the target for cases where it can replace text like "^" or "^Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, String user, NounTrait userTrait, String target, NounTrait targetTrait) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(target, targetTrait, false)), ur = new Replacer(userPattern, new BeingSubstitution(user, userTrait, true)); return ur.replace(tr.replace(message)); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given Group of users, that group's associated NounTrait, the given target, and their * NounTrait. The NounTrait for user only matters if it is first-person or second-person (in which case this uses * the plural form) or if the Group contains one member (in which case it uses any gendered pronouns specified by * userTrait); it uses {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the {@link Group} of users for cases where they can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the name of the target for cases where it can replace text like "^" or "^Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, Group user, NounTrait userTrait, String target, NounTrait targetTrait) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(target, targetTrait, false)), ur = new Replacer(userPattern, new BeingSubstitution(userTrait, true, user.members)); return ur.replace(tr.replace(message)); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given Group of users, that group's associated NounTrait, the given group of targets, and * that group's NounTrait. The NounTraits only matter if they are is first-person or second-person (in which case * this uses the plural form) or if a Group contains one member (in which case it uses any gendered pronouns * specified by userTrait or targetTrait); it uses {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the {@link Group} of users for cases where they can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the {@link Group} of targets for cases where they can replace text like "@" or "@Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, Group user, NounTrait userTrait, Group target, NounTrait targetTrait) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(targetTrait, false, target.members)), ur = new Replacer(userPattern, new BeingSubstitution(userTrait, true, user.members)); return ur.replace(tr.replace(message)); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given user, that user's associated NounTrait, the given Group of targets, and that * group's NounTrait. The NounTrait for target only matters if it is first-person or second-person (in which case * this uses the plural form) or if the Group contains one member (in which case it uses any gendered pronouns * specified by targetTrait); it uses {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the name of the user for cases where it can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the {@link Group} of targets for cases where they can replace text like "@" or "@Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @return a String resulting from the processing of message */ public static String transform(CharSequence message, String user, NounTrait userTrait, Group target, NounTrait targetTrait) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(targetTrait, false, target.members)), ur = new Replacer(userPattern, new BeingSubstitution(user, userTrait, true)); return ur.replace(tr.replace(message)); } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given user, their associated NounTrait, the given target, and their NounTrait. Also * replaces the nth occurrence of "~" with the matching nth item in extra, so the first "~" is replaced with the * first item in extra, the second "~" with the second item, and so on until one is exhausted. * @param message the message to transform; should contain "@", "^", "$", or "~" in it, at least, to be replaced * @param user the name of the user for cases where it can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the name of the target for cases where it can replace text like "^" or "^Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @param extra an array or vararg of String where the nth item in extra will replace the nth occurrence of "~" * @return a String resulting from the processing of message */ public static String transform(CharSequence message, String user, NounTrait userTrait, String target, NounTrait targetTrait, String... extra) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(target, targetTrait, false)), ur = new Replacer(userPattern, new BeingSubstitution(user, userTrait, true)); String text = ur.replace(tr.replace(message)); if(extra != null && extra.length > 0) { for (int i = 0; i < extra.length; i++) { text = text.replaceFirst("~", extra[i]); } } return text; } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given Group of users, that group's associated NounTrait, the given target, and their * NounTrait. Also replaces the nth occurrence of "~" with the matching nth item in extra, so the first "~" is * replaced with the first item in extra, the second "~" with the second item, and so on until one is exhausted. The * NounTrait for user only matters if it is first-person or second-person (in which case this uses the plural form) * or if the Group contains one member (in which case it uses any gendered pronouns specified by userTrait); it uses * {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the {@link Group} of users for cases where they can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the name of the target for cases where it can replace text like "^" or "^Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @param extra an array or vararg of String where the nth item in extra will replace the nth occurrence of "~" * @return a String resulting from the processing of message */ public static String transform(CharSequence message, Group user, NounTrait userTrait, String target, NounTrait targetTrait, String... extra) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(target, targetTrait, false)), ur = new Replacer(userPattern, new BeingSubstitution(userTrait, true, user.members)); String text = ur.replace(tr.replace(message)); if(extra != null && extra.length > 0) { for (int i = 0; i < extra.length; i++) { text = text.replaceFirst("~", extra[i]); } } return text; } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given Group of users, that group's associated NounTrait, the given group of targets, and * that group's NounTrait. Also replaces the nth occurrence of "~" with the matching nth item in extra, so the first * "~" is replaced with the first item in extra, the second "~" with the second item, and so on until one is * exhausted. The NounTraits only matter if they are is first-person or second-person (in which case * this uses the plural form) or if a Group contains one member (in which case it uses any gendered pronouns * specified by userTrait or targetTrait); it uses {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the {@link Group} of users for cases where they can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the {@link Group} of targets for cases where they can replace text like "@" or "@Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @param extra an array or vararg of String where the nth item in extra will replace the nth occurrence of "~" * @return a String resulting from the processing of message */ public static String transform(CharSequence message, Group user, NounTrait userTrait, Group target, NounTrait targetTrait, String... extra) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(targetTrait, false, target.members)), ur = new Replacer(userPattern, new BeingSubstitution(userTrait, true, user.members)); String text = ur.replace(tr.replace(message)); if(extra != null && extra.length > 0) { for (int i = 0; i < extra.length; i++) { text = text.replaceFirst("~", extra[i]); } } return text; } /** * Takes message and replaces any of the special terms this recognizes, like @, ^, and $, with the appropriately- * conjugated terms for the given user, that user's associated NounTrait, the given Group of targets, and that * group's NounTrait. Also replaces the nth occurrence of "~" with the matching nth item in extra, so the first "~" * is replaced with the first item in extra, the second "~" with the second item, and so on until one is exhausted. * The NounTrait for target only matters if it is first-person or second-person (in which case this uses the plural * form) or if the Group contains one member (in which case it uses any gendered pronouns specified by targetTrait); * it uses {@link NounTrait#GROUP} in any other case. * @param message the message to transform; should contain "@", "^", or "$" in it, at least, to be replaced * @param user the name of the user for cases where it can replace text like "@" or "@Name" * @param userTrait the {@link NounTrait} enum that determines how user should be referred to * @param target the {@link Group} of targets for cases where they can replace text like "@" or "@Name" * @param targetTrait the {@link NounTrait} enum that determines how the target should be referred to * @param extra an array or vararg of String where the nth item in extra will replace the nth occurrence of "~" * @return a String resulting from the processing of message */ public static String transform(CharSequence message, String user, NounTrait userTrait, Group target, NounTrait targetTrait, String... extra) { Replacer tr = new Replacer(targetPattern, new BeingSubstitution(targetTrait, false, target.members)), ur = new Replacer(userPattern, new BeingSubstitution(user, userTrait, true)); String text = ur.replace(tr.replace(message)); if(extra != null && extra.length > 0) { for (int i = 0; i < extra.length; i++) { text = text.replaceFirst("~", extra[i]); } } return text; } protected static final Pattern userPattern = Pattern.compile("({at_sign}\\\\@)|({caret_sign}\\\\\\^)|({dollar_sign}\\\\\\$)|({tilde_sign}\\\\~)|" + "({$$$}\\$\\$\\$)|({$$}\\$\\$)|({$}\\$)|({sss}@sss\\b)|({ss}@ss\\b)|({s}@s\\b)|({usi}@usi\\b)|({fves}@fves\\b)|" + "({name_s}@name_s\\b)|({Name_s}@Name_s\\b)|({name}@name\\b)|({Name}@Name\\b)|({i}@i\\b)|({I}@I\\b)|({me}@me\\b)|({Me}@Me\\b)|" + "({myself}@myself\\b)|({Myself}@Myself\\b)|({my}@my\\b)|({My}@My\\b)|({mine}@mine\\b)|({Mine}@Mine\\b)|({direct}@direct\\b)|" + "({Direct}@Direct\\b)|(?:@({Other}\\p{Lu}\\w*)\\b)|(?:@({other}\\p{Ll}\\w*)\\b)|({=name}@)"), targetPattern = Pattern.compile("({at_sign}\\\\@)|({caret_sign}\\\\\\^)|({dollar_sign}\\\\\\$)|({tilde_sign}\\\\~)|" + "({$$$}\\^\\$\\$\\$)|({$$}\\^\\$\\$)|({$}\\^\\$)|({sss}\\^sss\\b)|({ss}\\^ss\\b)|({s}\\^s\\b)|({usi}\\^usi\\b)|({fves}\\^fves\\b)|" + "({name_s}\\^name_s\\b)|({Name_s}\\^Name_s\\b)|({name}\\^name\\b)|({Name}\\^Name\\b)|({i}\\^i\\b)|({I}\\^I\\b)|({me}\\^me\\b)|({Me}\\^Me\\b)|" + "({myself}\\^myself\\b)|({Myself}\\^Myself\\b)|({my}\\^my\\b)|({My}\\^My\\b)|({mine}\\^mine\\b)|({Mine}\\^Mine\\b)|({direct}^direct\\b)|" + "({Direct}^Direct\\b)|(?:\\^({Other}\\p{Lu}\\w*)\\b)|(?:\\^({other}\\p{Ll}\\w*)\\b)|({=name}\\^)"); private static final HashMap irregular = new HashMap<>(64); /** * Adds a given {@code word}, which should start with a lower-case letter and use lower-case letters and underscores * only, to the dictionary this stores. The 6 additional arguments are used for first person singular ("I am"), * first person plural ("we are"), second person singular ("you are"), second person plural ("you are", the same * as the last one usually, but not always), third person singular ("he is"), third person plural ("they are"). * @param word the word to learn; must start with a letter and use only lower-case letters and underscores * @param firstPersonSingular the conjugated form of the word for first-person singular ("I do", "I am") * @param firstPersonPlural the conjugated form of the word for first-person plural ("we do", "we are") * @param secondPersonSingular the conjugated form of the word for second-person singular ("you do", "you are") * @param secondPersonPlural the conjugated form of the word for second-person plural ("you do", "you are") * @param thirdPersonSingular the conjugated form of the word for third-person singular ("he does", "he is") * @param thirdPersonPlural the conjugated form of the word for third-person plural and unspecified-gender singular ("they do", "they are") */ public static void learnIrregularWord(String word, String firstPersonSingular, String firstPersonPlural, String secondPersonSingular, String secondPersonPlural, String thirdPersonSingular, String thirdPersonPlural) { irregular.put(word, new String[]{firstPersonSingular, firstPersonPlural, secondPersonSingular, secondPersonPlural, thirdPersonSingular, thirdPersonSingular, thirdPersonSingular, thirdPersonPlural, thirdPersonSingular, thirdPersonSingular, thirdPersonPlural}); } static { learnIrregularWord("m", "'m", "'re", "'re", "'re", "'s", "'re"); learnIrregularWord("am", "am", "are", "are", "are", "is", "are"); learnIrregularWord("ve", "'ve", "'ve", "'ve", "'ve", "'s", "'ve"); learnIrregularWord("have", "have", "have", "have", "have", "has", "have"); learnIrregularWord("haven_t", "haven't", "haven't", "haven't", "haven't", "hasn't", "haven't"); learnIrregularWord("do", "do", "do", "do", "do", "does", "do"); learnIrregularWord("don_t", "don't", "don't", "don't", "don't", "doesn't", "don't"); learnIrregularWord("this", "this", "these", "this", "these", "this", "these"); } protected static class BeingSubstitution implements Substitution { public String term; public NounTrait trait; public boolean finisher; public BeingSubstitution() { term = "Joe"; trait = NounTrait.MALE_GENDER; finisher = true; } public BeingSubstitution(String term, NounTrait trait, boolean finish) { this.term = (term == null) ? "Nullberoth of the North" : term; this.trait = (trait == null) ? NounTrait.UNSPECIFIED_GENDER : trait; finisher = finish; } public BeingSubstitution(NounTrait firstTrait, boolean finish, String... terms) { int len; if (terms == null || (len = terms.length) <= 0) { term = "Nihilatia of Voidetica"; trait = (firstTrait == null) ? NounTrait.UNSPECIFIED_GENDER : firstTrait; finisher = finish; } else if (len == 1) { term = (terms[0] == null) ? "Nullberoth of the North" : terms[0]; trait = (trait == null) ? NounTrait.UNSPECIFIED_GENDER : firstTrait; finisher = finish; } else if (len == 2) { term = terms[0] + " and " + terms[1]; if (firstTrait == null) trait = NounTrait.GROUP; else { switch (firstTrait) { case FIRST_PERSON_PLURAL: case FIRST_PERSON_SINGULAR: trait = NounTrait.FIRST_PERSON_PLURAL; break; case SECOND_PERSON_PLURAL: case SECOND_PERSON_SINGULAR: trait = NounTrait.SECOND_PERSON_PLURAL; break; default: trait = NounTrait.GROUP; } } finisher = finish; } else { StringBuilder sb = new StringBuilder().append(terms[0]).append(", "); for (int i = 1; i < len - 1; i++) { sb.append(terms[i]).append(", "); } term = sb.append("and ").append(terms[len - 1]).toString(); if (firstTrait == null) trait = NounTrait.GROUP; else { switch (firstTrait) { case FIRST_PERSON_PLURAL: case FIRST_PERSON_SINGULAR: trait = NounTrait.FIRST_PERSON_PLURAL; break; case SECOND_PERSON_PLURAL: case SECOND_PERSON_SINGULAR: trait = NounTrait.SECOND_PERSON_PLURAL; break; default: trait = NounTrait.GROUP; } } finisher = finish; } } public static void appendCapitalized(String s, TextBuffer dest) { dest.append(Character.toUpperCase(s.charAt(0))); if(s.length() > 1) dest.append(s.substring(1)); } @Override public void appendSubstitution(MatchResult match, TextBuffer dest) { if(match.isCaptured("at_sign")) { dest.append(finisher ? "@" : "\\@"); } else if(match.isCaptured("caret_sign")) { dest.append(finisher ? "^" : "\\^"); } else if(match.isCaptured("dollar_sign")) { dest.append(finisher ? "$" : "\\$"); } else if(match.isCaptured("tilde_sign")) { dest.append(finisher ? "~" : "\\~"); } else if(match.isCaptured("name")) { dest.append(trait.nameText(term)); } else if(match.isCaptured("Name")) { appendCapitalized(trait.nameText(term), dest); } else if(match.isCaptured("name_s")) { dest.append(trait.name_sText(term)); } else if(match.isCaptured("Name_s")) { appendCapitalized(trait.name_sText(term), dest); } else if(match.isCaptured("i")) { dest.append(trait.iText()); } else if(match.isCaptured("I")) { appendCapitalized(trait.iText(), dest); } else if(match.isCaptured("me")) { dest.append(trait.meText()); } else if(match.isCaptured("Me")) { appendCapitalized(trait.meText(), dest); } else if(match.isCaptured("my")) { dest.append(trait.myText()); } else if(match.isCaptured("My")) { appendCapitalized(trait.myText(), dest); } else if(match.isCaptured("mine")) { dest.append(trait.mineText()); } else if(match.isCaptured("Mine")) { appendCapitalized(trait.mineText(), dest); } else if(match.isCaptured("myself")) { dest.append(trait.myselfText()); } else if(match.isCaptured("Myself")) { appendCapitalized(trait.myselfText(), dest); } else if(match.isCaptured("s")) { dest.append(trait.sText()); } else if(match.isCaptured("ss")) { dest.append(trait.ssText()); } else if(match.isCaptured("sss")) { dest.append(trait.sssText()); } else if(match.isCaptured("usi")) { dest.append(trait.usiText()); } else if(match.isCaptured("fves")) { dest.append(trait.fvesText()); } else if(match.isCaptured("$")) { dest.append(trait.$Text()); } else if(match.isCaptured("$$")) { dest.append(trait.$$Text()); } else if(match.isCaptured("$$$")) { dest.append(trait.$$$Text()); } else if(match.isCaptured("other")) { String[] others = irregular.get(match.group("other")); if(others != null && others.length == 11) dest.append(others[trait.ordinal()]); else match.getGroup(0, dest); } else if(match.isCaptured("Other")) { String[] others = irregular.get(match.group("Other").toLowerCase()); if(others != null && others.length == 11) appendCapitalized(others[trait.ordinal()], dest); else match.getGroup(0, dest); } else if(match.isCaptured("direct")) { dest.append(trait.directText(term)); } else if(match.isCaptured("Direct")) { appendCapitalized(trait.directText(term), dest); } else match.getGroup(0, dest); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy