예제 #1
0
 /// <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;
 }
예제 #2
0
파일: VocabUtils.cs 프로젝트: shoff/Rant
        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);
        }
예제 #3
0
파일: Rhymer.cs 프로젝트: Sloves/Rant
        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);
        }
예제 #4
0
파일: Rhymer.cs 프로젝트: W-h-a-t-s/Rant
        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;
        }
예제 #5
0
파일: RantPackage.cs 프로젝트: inkadnb/Rant
        /// <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;
            }
        }
예제 #6
0
            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);
                    }
                }
            }
예제 #7
0
        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);
            }
        }
예제 #8
0
        /// <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;
            }
        }