1 /** Generic Language Constructs. 2 See_Also: https://en.wikipedia.org/wiki/Predicate_(grammar) 3 4 Note that ! and ? are more definite sentence enders than . 5 6 TODO `isSomeString` => `isStringLike` 7 8 TODO Use static foreach to add declarations for all isX, for each X 9 10 See_Also: http://forum.dlang.org/thread/mgdtuxkuswfxxoithwxh@forum.dlang.org 11 */ 12 module nxt.lingua; 13 14 import std.traits : isSomeChar, isSomeString; 15 import std.algorithm.comparison : among; 16 import std.algorithm.iteration : uniq; 17 import std.array : array; 18 import std.conv; 19 20 // TODO add overload to std.algorithm.among that takes an immutable array as 21 // argument to prevent calls to aliasSeqOf 22 import std.meta : aliasSeqOf; 23 24 import nxt.languages: Lang; 25 26 @safe pure: 27 28 /** Computer Token Usage. */ 29 enum Usage 30 { 31 unknown, 32 definition, 33 reference, 34 call 35 } 36 37 /// ================ English Articles 38 39 /** English indefinite articles. */ 40 static immutable englishIndefiniteArticles = [`a`, `an`]; 41 42 /** English definite articles. */ 43 static immutable englishDefiniteArticles = [`the`]; 44 45 /** English definite articles. */ 46 static immutable englishArticles = englishIndefiniteArticles ~ englishDefiniteArticles; 47 48 bool isEnglishIndefiniteArticle(S)(S s) 49 { 50 return cast(bool)s.among!(aliasSeqOf!englishIndefiniteArticles); 51 } 52 53 bool isEnglishDefiniteArticle(S)(S s) 54 if (isSomeString!S) 55 { 56 return cast(bool)s.among!(aliasSeqOf!englishDefiniteArticles); 57 } 58 59 bool isEnglishArticle(S)(S s) 60 if (isSomeString!S) 61 { 62 return cast(bool)s.among!(aliasSeqOf!englishArticles); 63 } 64 65 /// ================ German Articles 66 67 /** German indefinite articles. */ 68 static immutable germanIndefiniteArticles = [`ein`, `eine`, `einer`, `einen`, `einem`, `eines`]; 69 70 /** German definite articles. */ 71 static immutable germanDefiniteArticles = [`der`, `die`, `das`, `den`, `dem`, `des`]; 72 73 /** German definite articles. */ 74 static immutable germanArticles = germanIndefiniteArticles ~ germanDefiniteArticles; 75 76 /** Check if $(D s) is a Vowel. */ 77 bool isGermanIndefiniteArticle(S)(S s) 78 if (isSomeString!S) 79 { 80 return cast(bool)s.among!(aliasSeqOf!germanIndefiniteArticles); 81 } 82 83 /** Check if $(D s) is a Vowel. */ 84 bool isGermanDefiniteArticle(S)(S s) 85 if (isSomeString!S) 86 { 87 return cast(bool)s.among!(aliasSeqOf!germanDefiniteArticles); 88 } 89 90 /** Check if $(D s) is a Vowel. */ 91 bool isGermanArticle(S)(S s) 92 if (isSomeString!C) 93 { 94 return cast(bool)s.among!(aliasSeqOf!germanArticles); 95 } 96 97 /// ================ Vowels 98 99 /** English vowel type. 100 * See_Also: https://simple.wikipedia.org/wiki/Vowel 101 */ 102 enum EnglishVowel { a, o, u, e, i, y, 103 A, O, U, E, I, Y } 104 105 /** English Vowels. */ 106 static immutable dchar[] englishVowels = ['a', 'o', 'u', 'e', 'i', 'y', 107 'A', 'O', 'U', 'E', 'I', 'Y']; 108 109 /** Check if `c` is a Vowel. */ 110 bool isEnglishVowel(const dchar c) nothrow @nogc 111 { 112 return cast(bool)c.among!(aliasSeqOf!englishVowels); 113 } 114 115 /** English Accented Vowels. */ 116 static immutable dchar[] englishAccentedVowels = ['é']; 117 118 /** Check if `c` is an Accented Vowel. */ 119 bool isEnglishAccentedVowel(const dchar c) nothrow @nogc 120 { 121 return cast(bool)c.among!(aliasSeqOf!englishAccentedVowels); 122 } 123 124 nothrow @nogc unittest 125 { 126 assert('é'.isEnglishAccentedVowel); 127 } 128 129 /** Swedish Hard Vowels. */ 130 static immutable swedishHardVowels = ['a', 'o', 'u', 'å', 131 'A', 'O', 'U', 'Å']; 132 133 /** Swedish Soft Vowels. */ 134 static immutable swedishSoftVowels = ['e', 'i', 'y', 'ä', 'ö', 135 'E', 'I', 'Y', 'Ä', 'Ö']; 136 137 /** Swedish Vowels. */ 138 static immutable swedishVowels = swedishHardVowels ~ swedishSoftVowels; 139 140 /** Check if `c` is a Swedish Vowel. */ 141 bool isSwedishVowel(const dchar c) nothrow @nogc 142 { 143 return cast(bool)c.among!(aliasSeqOf!swedishVowels); 144 } 145 146 /** Check if `c` is a Swedish hard vowel. */ 147 bool isSwedishHardVowel(const dchar c) nothrow @nogc 148 { 149 return cast(bool)c.among!(aliasSeqOf!swedishHardVowels); 150 } 151 152 /** Check if `c` is a Swedish soft vowel. */ 153 bool isSwedishSoftVowel(const dchar c) nothrow @nogc 154 { 155 return cast(bool)c.among!(aliasSeqOf!swedishSoftVowels); 156 } 157 158 /** Spanish Accented Vowels. */ 159 enum spanishAccentedVowels = ['á', 'é', 'í', 'ó', 'ú', 160 'Á', 'É', 'Í', 'Ó', 'Ú']; 161 162 /** Check if `c` is a Spanish Accented Vowel. */ 163 bool isSpanishAccentedVowel(const dchar c) nothrow @nogc 164 { 165 return cast(bool)c.among!(aliasSeqOf!spanishAccentedVowels); 166 } 167 168 /** Check if `c` is a Spanish Vowel. */ 169 bool isSpanishVowel(const dchar c) nothrow @nogc 170 { 171 return (c.isEnglishVowel || 172 c.isSpanishAccentedVowel); 173 } 174 175 nothrow @nogc unittest 176 { 177 assert('é'.isSpanishVowel); 178 } 179 180 /** Check if `c` is a Vowel in language $(D lang). */ 181 bool isVowel(const dchar c, Lang lang) nothrow @nogc 182 { 183 switch (lang) 184 { 185 case Lang.en: return c.isEnglishVowel; 186 case Lang.sv: return c.isSwedishVowel; 187 default: return c.isEnglishVowel; 188 } 189 } 190 191 nothrow @nogc unittest 192 { 193 assert(!'k'.isSwedishVowel); 194 assert('å'.isSwedishVowel); 195 } 196 197 /** English consonant type. 198 * See_Also: https://simple.wikipedia.org/wiki/Consonant 199 */ 200 enum EnglishConsonant { b, c, d, f, g, h, j, k, l, m, n, p, q, r, s, t, v, w, x } 201 202 /** English lowercase consontant characters. */ 203 static immutable dchar[] englishLowerConsonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x']; 204 205 /** English uppercase consontant characters. */ 206 static immutable dchar[] englishUpperConsonants = ['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X']; 207 208 /** English consontant characters. */ 209 static immutable dchar[] englishConsonants = englishLowerConsonants ~ englishUpperConsonants; 210 211 /** Check if `c` is a Consonant. */ 212 bool isEnglishConsonant(const dchar c) nothrow @nogc 213 { 214 return cast(bool)c.among!(aliasSeqOf!englishConsonants); 215 } 216 alias isSwedishConsonant = isEnglishConsonant; 217 218 nothrow @nogc unittest 219 { 220 assert('k'.isEnglishConsonant); 221 assert(!'å'.isEnglishConsonant); 222 } 223 224 /** English letters. */ 225 static immutable dchar[] englishLetters = englishVowels ~ englishConsonants; 226 227 /** Check if `c` is a letter. */ 228 bool isEnglishLetter(const dchar c) nothrow @nogc 229 { 230 return cast(bool)c.among!(aliasSeqOf!englishLetters); 231 } 232 alias isEnglish = isEnglishLetter; 233 234 nothrow @nogc unittest 235 { 236 assert('k'.isEnglishLetter); 237 assert(!'å'.isEnglishLetter); 238 } 239 240 static immutable englishDoubleConsonants = [`bb`, `dd`, `ff`, `gg`, `mm`, `nn`, `pp`, `rr`, `tt`, `ck`, `ft`]; 241 242 /** Check if `s` is an English Double consonant. */ 243 bool isEnglishDoubleConsonant(scope const(char)[] s) nothrow @nogc 244 { 245 return cast(bool)s.among!(`bb`, `dd`, `ff`, `gg`, `mm`, `nn`, `pp`, `rr`, `tt`, `ck`, `ft`); 246 } 247 248 /** Computer token. */ 249 enum TokenId 250 { 251 unknown, 252 253 keyword, 254 type, 255 constant, 256 comment, 257 variableName, 258 functionName, 259 builtinName, 260 templateName, 261 macroName, 262 aliasName, 263 enumeration, 264 enumerator, 265 constructor, 266 destructors, 267 operator, 268 } 269 270 /** Swedish Verb Inflection (conjugation of a verb). 271 * 272 * See_Also: http://www.101languages.net/swedish/swedish-verb-conjugator/ 273 * See_Also: http://www.verbix.com/webverbix/Swedish/springa.html 274 */ 275 enum SwedishVerbInflection 276 { 277 unknown, 278 } 279 280 /** Verb Form. 281 * 282 * See_Also: http://verb.woxikon.se/sv/springa 283 */ 284 enum VerbForm 285 { 286 unknown, 287 288 imperative, // Swedish example: spring 289 290 infinitive, // sv:infinitiv,grundform. Swedish example: springa 291 base = infinitive, 292 293 presentIndicative, // sv:presens. Swedish example: springer 294 295 presentParticiple, // sv:presens particip. Swedish example: springande 296 gerund = presentParticiple, // Form that functions as a noun. Source: https://en.wikipedia.org/wiki/Gerund 297 298 pastIndicative, // sv:imperfekt. Swedish example: sprang 299 preteritum = pastIndicative, 300 301 supinum, // Swedish example: sprungit 302 pastParticiple = supinum, 303 304 perfekt, // sv:perfekt. Swedish example: har sprungit 305 306 perfektParticiple, // sv:perfekt particip. Swedish example: sprungen 307 308 pluskvamperfekt, // sv:pluskvamperfekt. Swedish example: hade sprungit 309 310 futurum, // Swedish example:ska springa 311 312 futurumExaktum, // Swedish example:ska ha sprungit 313 futurumPerfect = futurumExaktum, 314 315 konditionalisI, // Swedish example:skulle springa 316 317 conditionalPerfect, // Swedish example:skulle ha sprungit 318 konditionalisII = conditionalPerfect, 319 } 320 321 /** Verb Instance. */ 322 struct Verb(S) 323 if (isSomeString!S) 324 { 325 S expr; 326 VerbForm form; 327 alias expr this; 328 } 329 330 /** Subject Count. */ 331 enum Count 332 { 333 unknown, 334 singular, 335 plural, 336 uncountable 337 } 338 339 struct Noun(S) 340 if (isSomeString!S) 341 { 342 S expr; 343 Count count; 344 alias expr this; 345 } 346 347 /** Comparation. 348 * See_Also: https://en.wikipedia.org/wiki/Comparison_(grammar) 349 */ 350 enum Comparation 351 { 352 unknown, 353 positive, 354 comparative, 355 superlative, 356 elative, 357 exzessive 358 } 359 360 struct Adjective(S) 361 if (isSomeString!S) 362 { 363 S expr; 364 Comparation comparation; 365 alias expr this; 366 } 367 368 /** English Tense. 369 * 370 * Same as "tempus" in Swedish. 371 * 372 * See_Also: http://www.ego4u.com/en/cram-up/grammar/tenses-graphic 373 * See_Also: http://www.ego4u.com/en/cram-up/grammar/tenses-examples 374 */ 375 enum Tense 376 { 377 unknown, 378 379 present, presens = present, // sv:nutid 380 past, preteritum = past, imperfekt = past, // sv:dåtid, https://en.wikipedia.org/wiki/Past_tense 381 future, futurum = future, // framtid, https://en.wikipedia.org/wiki/Future_tense 382 383 pastMoment, 384 presentMoment, // sv:plays 385 futureMoment, // [will|is going to|intends to] play 386 387 pastPeriod, 388 presentPeriod, 389 futurePeriod, 390 391 pastResult, 392 presentResult, 393 futureResult, 394 395 pastDuration, 396 presentDuration, 397 futureDuration, 398 } 399 alias Tempus = Tense; 400 401 nothrow @nogc 402 { 403 bool isPast(Tense tense) 404 { 405 with (Tense) 406 return cast(bool)tense.among!(past, pastMoment, pastPeriod, pastResult, pastDuration); 407 } 408 409 bool isPresent(Tense tense) 410 { 411 with (Tense) 412 return cast(bool)tense.among!(present, presentMoment, presentPeriod, presentResult, presentDuration); 413 } 414 415 bool isFuture(Tense tense) 416 { 417 with (Tense) 418 return cast(bool)tense.among!(future, futureMoment, futurePeriod, futureResult, futureDuration); 419 } 420 } 421 422 /** Part of a Sentence. */ 423 enum SentencePart 424 { 425 unknown, 426 subject, 427 predicate, 428 adverbial, 429 object, 430 } 431 432 enum Adverbial 433 { 434 unknown, 435 436 manner, // they were playing `happily` (sätts-adverbial in Swedish) 437 438 place, // we met in `London`, `at the beach` 439 space = place, 440 441 time, // they start work `at six thirty` 442 443 probability, // `perhaps` the weather will be fine 444 445 direction, // superman flew `in`, the car drove `out` (förändring av tillstånd in Swedish) 446 location, // are you `in`?, the ball is `out` (oföränderligt tillstånd in Swedish) 447 448 quantifier, // he weighs `63 kilograms` (måtts-adverbial in Swedish) 449 450 comparation, // (grads-adverbial in Swedish) 451 452 cause, // (orsaks-adverbial in Swedish) 453 454 circumstance, // (omständighets-adverbial in Swedish) 455 } 456 457 class Part 458 { 459 } 460 461 // class Predicate : Part 462 // { 463 // } 464 465 /** Article (of noun). 466 * 467 * See_Also: https://en.wikipedia.org/wiki/Article_(grammar) 468 */ 469 enum Article 470 { 471 unknown, ///< Unknown. 472 definite, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Definite_article 473 indefinite, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Indefinite_article 474 proper, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Proper_article 475 partitive, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Partitive_article. 476 negative, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Negative_article 477 zero, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Zero_article 478 } 479 480 class Subject : Part 481 { 482 Article article; 483 } 484 485 static immutable implies = [`in order to`]; 486 487 /** Subject Person. */ 488 enum Person 489 { 490 unknown, 491 first, 492 second, 493 third 494 } 495 496 /** Grammatical Gender. 497 * 498 * Called genus in Swedish. 499 * 500 * See_Also: https://en.wikipedia.org/wiki/Grammatical_gender 501 * See_Also: https://sv.wikipedia.org/wiki/Genus_(k%C3%B6nsbegrepp) 502 */ 503 enum Gender 504 { 505 unknown, 506 507 male, masculine = male, // maskulinum 508 509 female, feminine = female, // femininum 510 511 neutral, neuter = neutral, neutrum = neuter, // non-alive. for example: "något" 512 513 common, utrum = common, reale = utrum, // Present in Swedish. real/alive. for example: "någon" 514 } 515 516 /** (Grammatical) Mood. 517 * 518 * Sometimes also called mode. 519 * 520 * Named modus in Swedish. 521 * 522 * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood 523 * See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#mood 524 */ 525 enum Mood 526 { 527 unknown, 528 529 indicative, // indikativ in Swedish. Example: I eat pizza. 530 531 /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#subjunctive 532 subjunctive, // Example: if I were to eat more pizza, I would be sick. 533 conjunctive = subjunctive, // konjunktiv in Swedish 534 535 conditional, 536 optative, 537 538 /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#imperative 539 imperative, // imperativ in Swedish. Example: eat the pizza! 540 541 jussive, 542 potential, 543 inferential, 544 interrogative, 545 546 /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#wh-question 547 whQuestion, // Example: who is eating pizza? 548 549 /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#yn-question 550 ynQuestion, // Example: did you eat pizza? 551 } 552 553 /** Check if $(D mood) is a Realis Mood. 554 * 555 * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood#Realis_moods 556 */ 557 bool isRealis(Mood mood) @nogc nothrow 558 { 559 with (Mood) 560 { 561 return cast(bool)mood.among!(indicative); 562 } 563 } 564 565 enum realisMoods = [Mood.indicative]; 566 567 /** Check if $(D mood) is a Irrealis Mood. 568 * 569 * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood#Irrealis_moods 570 */ 571 bool isIrrealis(Mood mood) @nogc nothrow 572 { 573 with (Mood) 574 { 575 return cast(bool)mood.among!(subjunctive, 576 conditional, 577 optative, 578 imperative, 579 jussive, 580 potential, 581 inferential); 582 } 583 } 584 585 enum irrealisMoods = [Mood.subjunctive, 586 Mood.conditional, 587 Mood.optative, 588 Mood.imperative, 589 Mood.jussive, 590 Mood.potential, 591 Mood.inferential]; 592 593 /** English Negation Prefixes. 594 * 595 * See_Also: http://www.english-for-students.com/Negative-Prefixes.html 596 */ 597 static immutable englishNegationPrefixes = [ `un`, `non`, `dis`, `im`, `in`, `il`, `ir`, ]; 598 599 static immutable swedishNegationPrefixes = [ `icke`, `o`, ]; 600 601 /** English Noun Suffixes. 602 * 603 * See_Also: http://www.english-for-students.com/Noun-Suffixes.html 604 */ 605 static immutable adjectiveNounSuffixes = [ `ness`, `ity`, `ment`, `ance` ]; 606 static immutable verbNounSuffixes = [ `tion`, `sion`, `ment`, `ence` ]; 607 static immutable nounNounSuffixes = [ `ship`, `hood` ]; 608 static immutable allNounSuffixes = (adjectiveNounSuffixes ~ 609 verbNounSuffixes ~ 610 nounNounSuffixes ~ 611 [ `s`, `ses`, `xes`, `zes`, `ches`, `shes`, `men`, `ies`, ]); 612 613 /** English Verb Suffixes. */ 614 static immutable verbSuffixes = [ `s`, `ies`, `es`, `es`, `ed`, `ed`, `ing`, `ing`, ]; 615 616 /** English Adjective Suffixes. */ 617 static immutable adjectiveSuffixes = [ `er`, `est`, `er`, `est` ]; 618 619 /** English Job/Professin Title Suffixes. 620 * 621 * Typically built from noun or verb bases. 622 * 623 * See_Also: http://www.english-for-students.com/Job-Title-Suffixes.html 624 */ 625 static immutable jobTitleSuffixes = [ `or`, // traitor 626 `er`, // builder 627 `ist`, // typist 628 `an`, // technician 629 `man`, // dustman, barman 630 `woman`, // policewoman 631 `ian`, // optician 632 `person`, // chairperson 633 `sperson`, // spokesperson 634 `ess`, // waitress 635 `ive` // representative 636 ]; 637 638 /** English Linking Verbs in Nominative Form. 639 */ 640 static immutable englishLinkingVerbs = [`is`, `seem`, `look`, `appear to be`, `could be`]; 641 static immutable swedishLinkingVerbs = [`är`, `verkar`, `ser`, `kan vara`]; 642 643 /** English Word Suffixes. */ 644 static immutable wordSuffixes = [ allNounSuffixes ~ verbSuffixes ~ adjectiveSuffixes ].uniq.array; 645 646 /** Return string $(D word) in plural optionally in $(D count). */ 647 string inPlural(string word, int count = 2, 648 string pluralWord = null) 649 { 650 if (count == 1 || word.length == 0) 651 { 652 return word; // it isn't actually inPlural 653 } 654 if (pluralWord !is null) 655 { 656 return pluralWord; 657 } 658 switch (word[$ - 1]) 659 { 660 case 's': 661 case 'a', 'e', 'i', 'o', 'u': 662 return word ~ `es`; 663 case 'f': 664 return word[0 .. $-1] ~ `ves`; 665 case 'y': 666 return word[0 .. $-1] ~ `ies`; 667 default: 668 return word ~ `s`; 669 } 670 } 671 672 /** Return $(D s) lemmatized (normalized). 673 * 674 * See_Also: https://en.wikipedia.org/wiki/Lemmatisation 675 */ 676 S lemmatized(S)(S s) nothrow 677 if (isSomeString!S) 678 { 679 if (s.among!(`be`, `is`, `am`, `are`)) return `be`; 680 else if (s.among!(`do`, `does`)) return `do`; 681 else return s; 682 } 683 684 /** 685 TODO Reuse knet translation query instead. 686 */ 687 string negationIn(Lang lang) nothrow @nogc 688 { 689 switch (lang) with (Lang) 690 { 691 case en: return `not`; 692 case sv: return `inte`; 693 case de: return `nicht`; 694 default: return `not`; 695 } 696 } 697 698 enum Manner 699 { 700 // TODO add unknown 701 formal, 702 informal, 703 slang, 704 rude, 705 } 706 707 /** Grammatical Case. 708 * 709 * See_Also: https://en.wikipedia.org/wiki/Grammatical_case 710 */ 711 enum Case 712 { 713 unknown, 714 nominative, 715 genitive, 716 dative, 717 accusative, 718 ablative 719 } 720 721 /** English Subject Pronouns. 722 * 723 * See_Also: https://en.wikipedia.org/wiki/Subject_pronoun 724 */ 725 static immutable englishSubjectPronouns = [`I`, // 1st-person singular 726 `you`, // 2nd-person singular 727 `he`, `she`, `it`, // 3rd-person singular 728 `we`, // 1st-person plural 729 `they`, // 2nd-person plural 730 `what`, // interrogate singular (Object) 731 `who`]; // interrogate singular 732 733 /** Swedish Subject Pronouns. 734 * 735 * See_Also: https://en.wikipedia.org/wiki/Subject_pronoun 736 */ 737 static immutable swedishSubjectPronouns = [`jag`, // 1st-person singular 738 `du`, // 2nd-person singular 739 `han`, `hon`, `den`, `det`, // 3rd-person singular 740 `vi`, // 1st-person plural 741 `de`, // 2nd-person plural 742 `vad`, // interrogate singular (Object) 743 `vem`, // interrogate singular 744 `vilka`]; // interrogate plural 745 746 /** English Object Pronouns. 747 * 748 * See_Also: https://en.wikipedia.org/wiki/Object_pronoun 749 */ 750 static immutable englishObjectPronouns = [`me`, // 1st-person singular 751 `you`, // 2nd-person singular 752 `him,`, `her`, // 3rd-person singular 753 `us`, // 1st-person plural 754 `them`, // 2nd-person plural 755 `whom`]; // interrogate singular 756 757 /** Swedish Object Pronouns. 758 * 759 * See_Also: https://en.wikipedia.org/wiki/Object_pronoun 760 */ 761 static immutable swedishObjectPronouns = [`mig`, `dig`, 762 `honom,`, `henne`, 763 `oss`, 764 `dem`]; 765 766 enum Casing 767 { 768 unknown, 769 lower, 770 upper, 771 capitalized, 772 camel 773 }