Инструмент «Часть слова» SlimParser

tolka1

Пользователь
Регистрация
13.08.15
Сообщения
5
Реакции
0
Баллы
1
Я начал возвращаться к анализаторам текста и анализировать части текста. У меня есть действительно хороший парсер, который я буду использовать в Electron. Другим, создающим текстовые игры, это может понравиться. Есть простая ошибка, и у меня был ответ раньше, но его больше нет. Я использую регулярное выражение для извлечения именованных групп захвата. Единственная ошибка, которую я вижу в этом, заключается в том, что группы для indirectObject и DirectObject должны содержать любое количество символов и пробелов.

alert2 — разделитель будет последним словом в группе захвата.
alert3 - Там же.
alert4 — разделитель является предлогом.
alert5 — первый разделитель для DirectObject — это предлог, IndirectObject — последнее слово в группе захвата.

Код:
// This parser will return a parsedCommand object filled with usefull sentence parts. function SlimParser() { this.parsedCommand = { "patternType":null, "verb":null, "indirectObject":null, "directObject":null, "preposition":null, "error":false }; this.prepositionList = ['on', 'under', 'over', 'above', 'down', 'up', 'with', 'across', 'around', 'from', 'at', 'to', 'for', 'about']; } SlimParser.prototype.parse = function(command){ var commandArray = command.split(" "); if(commandArray.length == 1) { if(/(?<verb>[^ $]*)/.test(command)) { const matches = /(?<verb>[^ $]*)/.exec(command); this.parsedCommand.patternType = "V"; // verb this.parsedCommand.verb = matches.groups.verb; alert("in 1"); }else{ } }else{ if(!this.prepositionInStr(command)) { if(/(?<verb>[^ $]*)( the)? (?<directObject>[\w+]*)/.test(command)) { const matches = /(?<verb>[^ $]*)( the)? (?<directObject>[\w+]*)/.exec(command); this.parsedCommand.patternType = "VO"; // verb object this.parsedCommand.verb = matches.groups.verb; this.parsedCommand.directObject = matches.groups.directObject; alert("in 2"); } }else{ if(this.strIsPrepoistion(commandArray[1])) { if(/(?<verb>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)( the)? (?<directObject>[^ $]*)/.test(command)) { const matches = /(?<verb>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)( the)? (?<directObject>[^ $]*)/.exec(command); this.parsedCommand.patternType = "VPO"; // verb preposition object this.parsedCommand.verb = matches.groups.verb; this.parsedCommand.preposition = commandArray[1]; this.parsedCommand.directObject = matches.groups.directObject this.parsedCommand.preposition = this.prepositionFetch(command); alert("in 3"); } }else if(this.strIsPrepoistion(commandArray[commandArray.length - 1])) { if(/(?<verb>[^ $]*)( the)? (?<directObject>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)/.test(command)) { const matches = /(?<verb>[^ $]*)( the)? (?<directObject>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)/.exec(command); this.parsedCommand.patternType = "VOP"; // verb object preposition this.parsedCommand.verb = matches.groups.verb; this.parsedCommand.preposition = commandArray[commandArray.length - 1]; this.parsedCommand.directObject = matches.groups.directObject this.parsedCommand.indirectObject = matches.groups.indirectObject alert("in 4"); } }else{ if(/(?<verb>[^ $]*)( the)? (?<directObject>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)( the)? (?<indirectObject>[^ $]*)/.test(command)) { const matches = /(?<verb>[^ $]*)( the)? (?<directObject>[^ $]*) (on|under|over|above|down|up|with|across|around|from|at|to|for|about)( the)? (?<indirectObject>[^ $]*)/.exec(command); this.parsedCommand.patternType = "VOPO"; // verb object preposition object this.parsedCommand.verb = matches.groups.verb; this.parsedCommand.directObject = matches.groups.directObject this.parsedCommand.indirectObject = matches.groups.indirectObject this.parsedCommand.preposition = this.prepositionFetch(commandArray); alert("in 5"); } } } } return this.parsedCommand; }; SlimParser.prototype.prepositionInStr = function(command) { let prepositionAvailable = false; for(let i = 0; i <= this.prepositionList.length - 1; i++) { if(command.includes(this.prepositionList[i])) { prepositionAvailable = true; } } return prepositionAvailable; } SlimParser.prototype.strIsPrepoistion = function(val) { let isPreposition = false; for(let i = 0; i <= this.prepositionList.length - 1; i++) { if(val == this.prepositionList[i]) { isPreposition = true; } } return isPreposition; }; SlimParser.prototype.prepositionFetch = function(testArr) { let prepositionStr = ""; for(let i = 0; i<= testArr.length - 1; i++) { for(let y = 0; y <= this.prepositionList.length - 1; y++) { if(testArr[i] == this.prepositionList[y]) { prepositionStr = this.prepositionList[y]; } } } return prepositionStr; };
Код (разметка): я понятия не имею, как это написать в регулярном выражении. Спасибо.
Инструмент «Часть слова» SlimParser
 

teaser-click

Пользователь
Регистрация
15.05.15
Сообщения
3
Реакции
0
Баллы
1
Эй, спасибо за ответ. Мне нужно, чтобы ты кое-что проверил. У меня это работает довольно хорошо, но есть некоторые проблемы. Я не хотел включать элементы и все такое заранее. Это очень интересно, но все же может иметь большие недостатки.

github.com/JeremyBenson11/text-game-parser
 

Lembo

Пользователь
Регистрация
25.02.16
Сообщения
2
Реакции
0
Баллы
1
Вы ПОЧТИ на правильном пути, но слишком много об этом думаете.

Часто бессмысленно пытаться сделать грамматические конструкции частью вашей фиксированной логики. Это происходит потому, что используемые слова определяют грамматическую последовательность; таким образом, когда вы создали «Список препозиций», вы ДЕЙСТВИТЕЛЬНО приблизились к ответу.

Создавайте словари по типам слов, чтобы определить, какой тип слов предоставляет текущая структура.

Поскольку у вас есть слова или комбинации слов, которые вы хотите найти, сделайте это прямо здесь, с помощью справочных таблиц.

Кроме того, вы можете рассмотреть возможность использования для этого новых «классов» ECMAScript 6, поскольку многое из того, что вы вызываете, следует рассматривать как «статическое».

Вместо глагола я бы начал с действия, которое МОЖЕТ быть глаголом, но может быть и другими словами. Например «Север». Таким образом, пользователю не придется вводить «идти на север». Север также может быть существительным, которое, как «идти на север», то же самое, что просто сказать «север», но также может быть объединено с чем-то вроде «бежать на север», поэтому оно будет указано в обоих случаях.

Это очень похоже на то, как я сделал это в текстовом приключении, которое я когда-то писал для DOS («За чертой черты, история паломника»), которое только что обновили до JavaScript вместо Turbo Pascal 5.5.




Код:
Object { action: "go", firstArticle: "north" }
Object { action: "take", firstArticle: "silver key" }
Object { action: "light", firstArticle: "fireplace", verbFunction: "with", secondArticle: "tinder box" }


Код (разметка): Например:

console.log(new CmdParser("Go North")); console.log(new CmdParser("Take Silver Key")); console.log(new CmdParser("Light Fireplace with tinder box"));
Код (разметка): Выдает:

class CmdParser { static ignore = /\b(a|the|an)\b/gi; static directions = [ "north", "south", "east", "west", "up", "down" ]; static items = [ "bucket", "eels", "water", "silver key", "gold key", "bronze key", "brass key", "iron key", "fire", "lamp", "fireplace", "tinder box" ]; static dictionary = { action : CmdParser.directions.concat([ "go", "run", "get", "take", "put", "place", "pick up", "drop", "light" ]), firstArticle : CmdParser.items.concat(CmdParser.directions), secondArticle : CmdParser.items, conjunctions : [ "and", "or" ], verbFunction : [ "on", "in", "atop", "with" ] }; static rxStartPhrase = (word) => new RegExp("^" + word + "\\b", "i"); constructor(text) { text = text.replace(CmdParser.ignore, "").replace(/\s+/, " ").trim(); textLoop: while (text) { for (let [part, lookup] of Object.entries(CmdParser.dictionary)) { if (!this[part]) for (let word of lookup) { if (text.match(CmdParser.rxStartPhrase(word))) { this[part] = word; text = text.substr(word.length + 1); if (text) continue textLoop; else return; } } } text = text.substr(text.indexOf(" ") + 1); } } // CmdParser::constructor } // CmdParser
Код (разметка): Чтобы разобрать код, вы можете увидеть нашу статику, содержащую различные биты информации, используя concat для создания нашего «словаря по типу», если это необходимо.

Конструктор сначала очищает данные, сокращая все внутренние пробелы и внешние, а также удаляя все слова, которые следует игнорировать. СНАЧАЛА уберите слова игнорирования с дороги.

Мы циклически работаем до тех пор, пока есть текст, просматривая словарь по типу (части). Если часть уже определена, пропустите ее. В противном случае проверьте совпадения слов. Регулярное выражение соответствия слов проверяет идеальное совпадение от начала «текста» до конца слова. Если он найден, мы записываем его как текущую «часть», удаляем его и пробел после «текста». Если текст все еще есть, «продолжить» самый внешний цикл, если нет, преждевременный выход через возврат.

Если текущее слово не имеет совпадений в нашем словаре, мы удаляем слово и пробел после него и продолжаем цикл.

Пытаться угадать грамматику до того, как ты узнаешь слова, это... ну, приведет к неприятностям. Словарь ПЕРВЫЙ.
 
Сверху Снизу