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

  • Автор темы tolka1
  • 36
  • Обновлено
  • 13, May 2024
  • #1
Я начал возвращаться к анализаторам текста и анализировать части текста.

У меня есть действительно хороший парсер, который я буду использовать в Electron.

Другим, создающим текстовые игры, это может понравиться.

Есть простая ошибка, и у меня был ответ раньше, но его больше нет.

Я использую регулярное выражение для извлечения именованных групп захвата.

Единственная ошибка, которую я вижу в этом, заключается в том, что группы для indirectObject и DirectObject должны содержать любое количество символов и пробелов.

alert2 — разделитель будет последним словом в группе захвата.

alert3 - Там же.

alert4 — разделитель является предлогом.

alert5 — первый разделитель для DirectObject — это предлог, IndirectObject — последнее слово в группе захвата.

 // This parser will return a parsedCommand object filled with usefull sentence parts.

// bug - All the regex commands need to allow directObject and indirectObject to be any number of words including spaces, to match 'red car.' Prepositions can be used to disambiguate.

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(" ");

// prepositions: on|under|over|above|down|up|with|across|from|at|to|for|about

// Prepositions help make regex queries unique, due to placement in sentence.

// <verb> the(opt) <directObj> <preposition> the(opt) <indirectObj>

// <verb> <preposition> the(opt) <directObj>

// <verb> the(opt) <directObj> <preposition>

// <verb> the(opt) <directObj>

// <verb>

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{

// throw error

}

// end single verb pattern

}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");

}

// end patterns without preposition

}else{

// patterns with prepositions

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");

}

}

// end patterns with prepositions

}

// end other patterns

}

return this.parsedCommand;

};

// test for a preposition in string

SlimParser.prototype.prepositionInStr = function(command)

{

// test if preposition available

let prepositionAvailable = false;

for(let i = 0; i <= this.prepositionList.length - 1; i++)

{

if(command.includes(this.prepositionList[i]))

{

prepositionAvailable = true;

}

}

return prepositionAvailable;

// end preposition fetch

}

SlimParser.prototype.strIsPrepoistion = function(val)

{

// test if str word is a preposition

let isPreposition = false;

for(let i = 0; i <= this.prepositionList.length - 1; i++)

{

if(val == this.prepositionList[i])

{

isPreposition = true;

}

}

return isPreposition;

// end test if str word is a preposition

};

// This function will return preposition used in command

SlimParser.prototype.prepositionFetch = function(testArr)

{

// every command has exactly one preposition or parse error thrown.

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;

// end preposition fetch

};
Код (разметка): я понятия не имею, как это написать в регулярном выражении.

Спасибо.

tolka1


Рег
13 Aug, 2015

Тем
2

Постов
5

Баллов
25
  • 07, Jun 2024
  • #2
Эй, спасибо за ответ. Мне нужно, чтобы ты кое-что проверил. У меня это работает довольно хорошо, но есть некоторые проблемы. Я не хотел включать элементы и все такое заранее. Это очень интересно, но все же может иметь большие недостатки. github.com/JeremyBenson11/text-game-parser
 

teaser-click


Рег
15 May, 2015

Тем
1

Постов
3

Баллов
13
  • 07, Jun 2024
  • #3
Вы ПОЧТИ на правильном пути, но слишком много об этом думаете. Часто бессмысленно пытаться сделать грамматические конструкции частью вашей фиксированной логики.

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

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

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

Кроме того, вы можете рассмотреть возможность использования для этого новых «классов» 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 для создания нашего «словаря по типу», если это необходимо.

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

СНАЧАЛА уберите слова игнорирования с дороги. Мы циклически работаем до тех пор, пока есть текст, просматривая словарь по типу (части). Если часть уже определена, пропустите ее. В противном случае проверьте совпадения слов.

Регулярное выражение соответствия слов проверяет идеальное совпадение от начала «текста» до конца слова.

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

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

Пытаться угадать грамматику до того, как ты узнаешь слова, это.

ну, приведет к неприятностям.

Словарь ПЕРВЫЙ.
 

Lembo


Рег
25 Feb, 2016

Тем
1

Постов
2

Баллов
12
Тем
49554
Комментарии
57426
Опыт
552966

Интересно