/// <summary> /// Creates a new RantDictionaryEntry object from the specified data. /// </summary> /// <param name="terms">The terms in the entry.</param> /// <param name="classes">The classes associated with the entry.</param> /// <param name="weight">The weight of the entry.</param> public RantDictionaryEntry(RantDictionaryTerm[] terms, IEnumerable<string> classes, int weight = 1) { _terms = terms; _classes = new HashSet<string>(); _optionalClasses = new HashSet<string>(); foreach(var c in classes) { if (c.EndsWith("?")) { var trimmed = VocabUtils.GetString(c.Substring(0, c.Length - 1)); _optionalClasses.Add(trimmed); _classes.Add(trimmed); } else { _classes.Add(VocabUtils.GetString(c)); } } Weight = weight; }
public static int RhymeIndex(RantDictionaryTerm baseValue, RantDictionaryTerm testValue) { if (baseValue == null || testValue == null) { return(0); } var baseParts = baseValue.PronunciationParts; var testParts = testValue.PronunciationParts; int index = 0; int len = Math.Min(baseParts.Length, testParts.Length); for (int i = 0; i < len; i++) { if (baseParts[baseParts.Length - (i + 1)] == testParts[testParts.Length - (i + 1)]) { index++; } else { return(index); } } return(index); }
public bool Rhyme(RantDictionaryTerm term1, RantDictionaryTerm term2) { bool hasStress = term1.Pronunciation.IndexOf('"') > -1 && term2.Pronunciation.IndexOf('"') > -1; // syllables after the stress are the same if (_allowedRhymes.Contains(RhymeType.Perfect) && hasStress) { var pron1 = term1.Pronunciation.Substring(term1.Pronunciation.IndexOf('"')).Replace("-", string.Empty); var pron2 = term2.Pronunciation.Substring(term2.Pronunciation.IndexOf('"')).Replace("-", string.Empty); pron1 = GetFirstVowelSound(pron1); pron2 = GetFirstVowelSound(pron2); if (pron1 == pron2) { return(true); } } // last syllables are the same if (_allowedRhymes.Contains(RhymeType.Syllabic)) { if (term1.Syllables.Last() == term2.Syllables.Last()) { return(true); } } // penultimate syllable is stressed but does not rhyme, last syllable rhymes if (_allowedRhymes.Contains(RhymeType.Weak) && hasStress) { if ( term1.SyllableCount >= 2 && term2.SyllableCount >= 2 && term1.Syllables[term1.SyllableCount - 2].IndexOf('"') > -1 && term2.Syllables[term2.SyllableCount - 2].IndexOf('"') > -1 && GetFirstVowelSound(term1.Syllables.Last()) == GetFirstVowelSound(term2.Syllables.Last()) ) { return(true); } } if (_allowedRhymes.Contains(RhymeType.Semirhyme)) { if (Math.Abs(term1.SyllableCount - term2.SyllableCount) == 1) { var longestWord = term1.SyllableCount > term2.SyllableCount ? term1 : term2; var shortestWord = term1.SyllableCount > term2.SyllableCount ? term2 : term1; if ( GetFirstVowelSound(longestWord.Syllables[longestWord.SyllableCount - 2]) == GetFirstVowelSound(shortestWord.Syllables.Last())) { return(true); } } } // psuedo-sound similar if (_allowedRhymes.Contains(RhymeType.Forced)) { var distance = LevenshteinDistance( term1.Value.GenerateDoubleMetaphone(), term2.Value.GenerateDoubleMetaphone() ); if (distance <= 1) { return(true); } } // matching final consonants if (_allowedRhymes.Contains(RhymeType.SlantRhyme)) { // WE ARE REVERSING THESE STRINGS OK string word1 = new string(term1.Value.Reverse().ToArray()); string word2 = new string(term2.Value.Reverse().ToArray()); if (GetFirstConsonants(word1) == GetFirstConsonants(word2)) { return(true); } } // matching first consonants if (_allowedRhymes.Contains(RhymeType.Alliteration)) { if (GetFirstConsonants(term1.Value) == GetFirstConsonants(term2.Value)) { return(true); } } // matching all consonants if (_allowedRhymes.Contains(RhymeType.Pararhyme)) { if (term1.Value .Where(x => !_vowels.Contains(x)) .SequenceEqual( term2.Value .Where(x => !_vowels.Contains(x)) )) { return(true); } } return(false); }
public bool Rhyme(RantDictionaryTerm term1, RantDictionaryTerm term2) { bool hasStress = term1.Pronunciation.IndexOf('"') > -1 && term2.Pronunciation.IndexOf('"') > -1; // syllables after the stress are the same if (IsEnabled(RhymeFlags.Perfect) && hasStress) { var pron1 = term1.Pronunciation.Substring(term1.Pronunciation.IndexOf('"')).Replace("-", string.Empty); var pron2 = term2.Pronunciation.Substring(term2.Pronunciation.IndexOf('"')).Replace("-", string.Empty); pron1 = GetFirstVowelSound(pron1); pron2 = GetFirstVowelSound(pron2); if (pron1 == pron2) return true; } // last syllables are the same if (IsEnabled(RhymeFlags.Syllabic)) { if (term1.Syllables.Last() == term2.Syllables.Last()) return true; } // penultimate syllable is stressed but does not rhyme, last syllable rhymes if (IsEnabled(RhymeFlags.Weak) && hasStress) { if ( term1.SyllableCount >= 2 && term2.SyllableCount >= 2 && term1.Syllables[term1.SyllableCount - 2].IndexOf('"') > -1 && term2.Syllables[term2.SyllableCount - 2].IndexOf('"') > -1 && GetFirstVowelSound(term1.Syllables.Last()) == GetFirstVowelSound(term2.Syllables.Last()) ) return true; } if (IsEnabled(RhymeFlags.Semirhyme)) { if (Math.Abs(term1.SyllableCount - term2.SyllableCount) == 1) { var longestWord = term1.SyllableCount > term2.SyllableCount ? term1 : term2; var shortestWord = term1.SyllableCount > term2.SyllableCount ? term2 : term1; if ( GetFirstVowelSound(longestWord.Syllables[longestWord.SyllableCount - 2]) == GetFirstVowelSound(shortestWord.Syllables.Last())) return true; } } // psuedo-sound similar if (IsEnabled(RhymeFlags.Forced)) { var distance = LevenshteinDistance( term1.Value.GenerateDoubleMetaphone(), term2.Value.GenerateDoubleMetaphone() ); if (distance <= 1) return true; } // matching final consonants if (IsEnabled(RhymeFlags.SlantRhyme)) { // WE ARE REVERSING THESE STRINGS OK string word1 = new string(term1.Value.Reverse().ToArray()); string word2 = new string(term2.Value.Reverse().ToArray()); if (GetFirstConsonants(word1) == GetFirstConsonants(word2)) return true; } // matching first consonants if (IsEnabled(RhymeFlags.Alliteration)) { if (GetFirstConsonants(term1.Value) == GetFirstConsonants(term2.Value)) return true; } // matching all consonants if (IsEnabled(RhymeFlags.Pararhyme)) { if (term1.Value .Where(x => !_vowels.Contains(x)) .SequenceEqual( term2.Value .Where(x => !_vowels.Contains(x)) )) return true; } return false; }
/// <summary> /// Loads a package from the specified stream and returns it as a RantPackage object. /// </summary> /// <param name="source">The stream to load the package data from.</param> /// <returns></returns> public static RantPackage Load(Stream source) { using (var reader = new EasyReader(source)) { if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != Magic) throw new InvalidDataException("File is corrupt."); int numPatterns = reader.ReadInt32(); int numTables = reader.ReadInt32(); if (numPatterns < 0 || numTables < 0) throw new InvalidDataException("File is corrupt."); var pkg = new RantPackage(); // Patterns for (int i = 0; i < numPatterns; i++) { var name = reader.ReadString(); var code = reader.ReadString(); pkg.AddPattern(new RantPattern(name, RantPatternSource.String, code)); } // Tables for (int i = 0; i < numTables; i++) { var name = reader.ReadString(); var subs = reader.ReadStringArray(); int numEntries = reader.ReadInt32(); var hiddenClasses = reader.ReadStringArray(); var entries = new RantDictionaryEntry[numEntries]; for (int j = 0; j < numEntries; j++) { int weight = reader.ReadInt32(); bool flags = reader.ReadBoolean(); // unused int numTerms = reader.ReadInt32(); var terms = new RantDictionaryTerm[numTerms]; for (int k = 0; k < numTerms; k++) { var value = reader.ReadString(); var pron = reader.ReadString(); terms[k] = new RantDictionaryTerm(value, pron); } var classes = reader.ReadStringArray(); entries[j] = new RantDictionaryEntry(terms, classes, weight); } pkg.AddTable(new RantDictionaryTable(name, subs, entries, hiddenClasses)); } return pkg; } }
public static void ReadTerms(string origin, string str, int len, int line, ref int i, RantDictionaryTable table, RantDictionaryEntry activeTemplate, Dictionary <string, RantDictionaryEntry> templates, out RantDictionaryEntry result) { SkipSpace(str, len, ref i); int t = 0; var terms = new RantDictionaryTerm[table.TermsPerEntry]; int split = -1; char c = '\0'; var buffer = new StringBuilder(); var white = new StringBuilder(); while (i < len) { switch (c = str[i++]) { // Inline comment case '#': goto done; // Phrasal split operator case '+': if (split > -1) { throw new RantTableLoadException(origin, line, i, "err-table-multiple-splits"); } white.Length = 0; split = buffer.Length; SkipSpace(str, len, ref i); break; // Term reference case '[': { SkipSpace(str, len, ref i); if (i >= len) { throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference"); } int start = i; if (white.Length > 0) { buffer.Append(white); white.Length = 0; } switch (str[i++]) { // Current term from active template case ']': if (t == -1) { throw new RantTableLoadException(origin, line, start + 1, "err-table-no-template"); } buffer.Append(activeTemplate[t].Value); break; // Custom term from active template case '.': { if (activeTemplate == null) { throw new RantTableLoadException(origin, line, start + 1, "err-table-no-template"); } while (i < len && IsValidSubtypeChar(str[i])) { i++; // Read subtype name } if (str[i] != ']') { throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference"); } string subName = str.Substring(start + 1, i - start - 1); if (subName.Length == 0) { throw new RantTableLoadException(origin, line, start + 1, "err-table-empty-subtype-reference"); } int templateSubIndex = table.GetSubtypeIndex(subName); if (templateSubIndex == -1) { throw new RantTableLoadException(origin, line, start + 1, "err-table-nonexistent-subtype", subName); } // Add term value to buffer buffer.Append(activeTemplate[templateSubIndex].Value); i++; // Skip past closing bracket break; } // It is probably a reference to another entry, let's see. default: { while (i < len && IsValidSubtypeChar(str[i]) || str[i] == '.') { i++; } if (str[i] != ']') { throw new RantTableLoadException(origin, line, i, "err-table-incomplete-term-reference"); } var id = str.Substring(start, i - start).Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); switch (id.Length) { // It's just a template ID. case 1: { if (!templates.TryGetValue(id[0], out RantDictionaryEntry entry)) { throw new RantTableLoadException(origin, line, start + 1, "err-table-entry-not-found"); } // Append term value to buffer buffer.Append(entry[t].Value); break; } // Template ID and custom subtype case 2: { if (!templates.TryGetValue(id[0], out RantDictionaryEntry entry)) { throw new RantTableLoadException(origin, line, start + 1, "err-table-entry-not-found"); } int templateSubIndex = table.GetSubtypeIndex(id[1]); if (templateSubIndex == -1 || templateSubIndex >= table.TermsPerEntry) { throw new RantTableLoadException(origin, line, start + 1, "err-table-nonexistent-subtype", id[1]); } buffer.Append(entry[templateSubIndex].Value); break; } // ??? default: throw new RantTableLoadException(origin, line, start + 1, "err-table-invalid-term-reference"); } i++; // Skip past closing bracket break; } } break; } case '\\': { if (white.Length > 0) { buffer.Append(white); white.Length = 0; } switch (c = str[i++]) { case 'n': buffer.Append('\n'); continue; case 'r': buffer.Append('\r'); continue; case 't': buffer.Append('\t'); continue; case 'v': buffer.Append('\v'); continue; case 'f': buffer.Append('\f'); continue; case 'b': buffer.Append('\b'); continue; case 's': buffer.Append(' '); continue; case 'u': { if (i + 4 > len) { throw new RantTableLoadException(origin, line, i + 1, "err-table-incomplete-escape"); } if (!ushort.TryParse(str.Substring(i, 4), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out ushort codePoint)) { throw new RantTableLoadException(origin, line, i + 1, "err-table-unrecognized-codepoint"); } buffer.Append((char)codePoint); i += 4; continue; } case 'U': { if (i + 8 > len) { throw new RantTableLoadException(origin, line, i + 1, "err-table-incomplete-escape"); } if (!Util.TryParseSurrogatePair(str.Substring(i, 8), out char high, out char low)) { throw new RantTableLoadException(origin, line, i + 1, "err-table-unrecognized-codepoint"); } buffer.Append(high).Append(low); i += 8; continue; } default: buffer.Append(c); continue; } continue; } case ',': if (t >= terms.Length) { throw new RantTableLoadException(origin, line, i, "err-table-too-many-terms", terms.Length, t); } terms[t++] = new RantDictionaryTerm(buffer.ToString(), split); buffer.Length = 0; white.Length = 0; split = -1; SkipSpace(str, len, ref i); break; default: if (char.IsWhiteSpace(c)) { white.Append(c); } else { if (white.Length > 0) { buffer.Append(white); white.Length = 0; } buffer.Append(c); } continue; } } done: if (t != terms.Length - 1) { throw new RantTableLoadException(origin, line, i, "err-table-too-few-terms", terms.Length, t + 1); } terms[t] = new RantDictionaryTerm(buffer.ToString()); result = new RantDictionaryEntry(terms); // Add classes from template if (activeTemplate != null) { foreach (string cl in activeTemplate.GetRequiredClasses()) { result.AddClass(cl, false); } foreach (string cl in activeTemplate.GetOptionalClasses()) { result.AddClass(cl, true); } } }
internal override void DeserializeData(EasyReader reader) { this.Name = reader.ReadString(); this.Language = reader.ReadString(); this.TermsPerEntry = reader.ReadInt32(); for (int i = 0; i < TermsPerEntry; i++) { foreach (var subtype in reader.ReadStringArray()) { AddSubtype(subtype, i); } } _hidden.AddRange(reader.ReadStringArray()); int numEntries = reader.ReadInt32(); for (int i = 0; i < numEntries; i++) { var terms = new RantDictionaryTerm[TermsPerEntry]; for (int j = 0; j < TermsPerEntry; j++) { var value = reader.ReadString(); var pron = reader.ReadString(); int valueSplit = reader.ReadInt32(); int pronSplit = reader.ReadInt32(); terms[j] = new RantDictionaryTerm(value, pron, valueSplit, pronSplit); } float weight = reader.ReadSingle(); var entry = new RantDictionaryEntry(terms) { Weight = weight }; foreach (var reqClass in reader.ReadStringArray()) { entry.AddClass(reqClass, false); } foreach (var optClass in reader.ReadStringArray()) { entry.AddClass(optClass, true); } int metaCount = reader.ReadInt32(); for (int j = 0; j < metaCount; j++) { bool isArray = reader.ReadBoolean(); var key = reader.ReadString(); if (isArray) { entry.SetMetadata(key, reader.ReadStringArray()); } else { entry.SetMetadata(key, reader.ReadString()); } } AddEntry(entry); } }
/// <summary> /// Loads a package from the specified stream and returns it as a RantPackage object. /// </summary> /// <param name="source">The stream to load the package data from.</param> /// <returns></returns> public static RantPackage Load(Stream source) { using (var reader = new EasyReader(source)) { var magic = Encoding.ASCII.GetString(reader.ReadBytes(4)); if (magic == OLD_MAGIC) return LoadOldPackage(reader); if (magic != MAGIC) throw new InvalidDataException("File is corrupt."); var package = new RantPackage(); var version = reader.ReadUInt32(); if (version != PACKAGE_VERSION) throw new InvalidDataException("Invalid package version: " + version); var compress = reader.ReadBoolean(); var size = reader.ReadInt32(); var data = reader.ReadBytes(size); if (compress) data = EasyCompressor.Decompress(data); var doc = BsonDocument.Read(data); var info = doc["info"]; if (info == null) throw new InvalidDataException("Metadata is missing from package."); package.Title = info["title"]; package.ID = info["id"]; package.Version = RantPackageVersion.Parse(info["version"]); package.Description = info["description"]; package.Authors = (string[])info["authors"]; package.Tags = (string[])info["tags"]; var deps = info["dependencies"]; if (deps != null && deps.IsArray) { for(int i = 0; i < deps.Count; i++) { var dep = deps[i]; var depId = dep["id"].Value; var depVersion = dep["version"].Value; bool depAllowNewer = (bool)dep["allow-newer"].Value; package.AddDependency(new RantPackageDependency(depId.ToString(), depVersion.ToString()) { AllowNewer = depAllowNewer }); } } var patterns = doc["patterns"]; if(patterns != null) { var names = patterns.Keys; foreach (string name in names) package.AddPattern(new RantPattern(name, RantPatternOrigin.File, patterns[name])); } var tables = doc["tables"]; if(tables != null) { var names = tables.Keys; foreach(string name in names) { var table = tables[name]; string tableName = table["name"]; string[] tableSubs = (string[])table["subs"]; string[] hiddenClasses = (string[])table["hidden"]; var entries = new List<RantDictionaryEntry>(); var entryList = table["entries"]; for(var i = 0; i < entryList.Count; i++) { var loadedEntry = entryList[i]; int weight = 1; if (loadedEntry.HasKey("weight")) weight = (int)loadedEntry["weight"].Value; string[] requiredClasses = (string[])loadedEntry["classes"]; string[] optionalClasses = (string[])loadedEntry["optional_classes"]; var terms = new List<RantDictionaryTerm>(); var termList = loadedEntry["terms"]; for(var j = 0; j < termList.Count; j++) { var t = new RantDictionaryTerm(termList[j]["value"], termList[j]["pron"]); terms.Add(t); } var entry = new RantDictionaryEntry( terms.ToArray(), requiredClasses.Concat(optionalClasses.Select(x => x + "?")), weight ); entries.Add(entry); } var rantTable = new RantDictionaryTable( tableName, tableSubs, entries, hiddenClasses ); package.AddTable(rantTable); } } return package; } }