我試圖弄清楚如何將這種格式的字串決議為任意深度的樹狀資料結構。然后隨機造句。
"{{Hello,Hi,Hey} {world,earth},{Goodbye,farewell} {planet,rock,globe{.,!}}}"
在哪里
, means or
{ means expand
} means collapse up to parent
例如,我想得到這樣的輸出:
1) hello world planet.
2) hi earth globe!
3) goodby planet.
and etc.
uj5u.com熱心網友回復:
必須決議輸入字串。由于它可以包含嵌套的大括號,我們需要一個遞回決議器。但首先,我們需要一個資料模型來表示樹結構。
我們可以在這棵樹中擁有三種不同型別的專案:文本、表示序列的串列和表示選擇的串列。讓我們從這個抽象基類派生三個類:
abstract public class TreeItem
{
public abstract string GetRandomSentence();
}
將TextItem類簡單地回傳其“隨機一句”文本:
public class TextItem : TreeItem
{
public TextItem(string text)
{
Text = text;
}
public string Text { get; }
public override string GetRandomSentence()
{
return Text;
}
}
該序列連接其專案的文本:
public class SequenceItem : TreeItem
{
public SequenceItem(List<TreeItem> items)
{
Items = items;
}
public List<TreeItem> Items { get; }
public override string GetRandomSentence()
{
var sb = new StringBuilder();
foreach (var item in Items) {
sb.Append(item.GetRandomSentence());
}
return sb.ToString();
}
}
選擇項是唯一一項使用隨機性從串列中隨機選擇一項的項:
public class ChoiceItem : TreeItem
{
private static readonly Random _random = new();
public ChoiceItem(List<TreeItem> items)
{
Items = items;
}
public List<TreeItem> Items { get; }
public override string GetRandomSentence()
{
int index = _random.Next(Items.Count);
return Items[index].GetRandomSentence();
}
}
請注意,序列和選擇項都GetRandomSentence()遞回呼叫它們的項以遞回下降樹。
這是容易的部分。現在讓我們創建一個決議器。
public class Parser
{
enum Token { Text, LeftBrace, RightBrace, Comma, EndOfString }
int _index;
string _definition;
Token _token;
string _text; // If token is Token.Text;
public TreeItem Parse(string definition)
{
_index = 0;
_definition = definition;
GetToken();
return Choice();
}
private void GetToken()
{
if (_index >= _definition.Length) {
_token = Token.EndOfString;
return;
}
switch (_definition[_index]) {
case '{':
_index ;
_token = Token.LeftBrace;
break;
case '}':
_index ;
_token = Token.RightBrace;
break;
case ',':
_index ;
_token = Token.Comma;
break;
default:
int startIndex = _index;
do {
_index ;
} while (_index < _definition.Length & !"{},".Contains(_definition[_index]));
_text = _definition[startIndex.._index];
_token = Token.Text;
break;
}
}
private TreeItem Choice()
{
var items = new List<TreeItem>();
while (_token != Token.EndOfString && _token != Token.RightBrace) {
items.Add(Sequence());
if (_token == Token.Comma) {
GetToken();
}
}
if (items.Count == 0) {
return new TextItem("");
}
if (items.Count == 1) {
return items[0];
}
return new ChoiceItem(items);
}
private TreeItem Sequence()
{
var items = new List<TreeItem>();
while (true) {
if (_token == Token.Text) {
items.Add(new TextItem(_text));
GetToken();
} else if (_token == Token.LeftBrace) {
GetToken();
items.Add(Choice());
if (_token == Token.RightBrace) {
GetToken();
}
} else {
break;
}
}
if (items.Count == 0) {
return new TextItem("");
}
if (items.Count == 1) {
return items[0];
}
return new SequenceItem(items);
}
}
It consists of a lexer, i.e., a low level mechanism to split the input text into tokens. We have have four kinds of tokens: text, "{", "}" and ",". We represent these tokens as
enum Token { Text, LeftBrace, RightBrace, Comma, EndOfString }
We also have added a EndOfString token to tell the parser that the end of the input string was reached. When the token is Text we store this text in the field _text. The lexer is implemented by the GetToken() method which has no return value and instead sets the _token field, to make the current token available in the two parsing methods Choice() and Sequence().
One difficulty is that when we encounter an item, we do not know whether it is a single item or whether it is part of a sequence or a choice. We assume that the whole sentence definition is a choice consisting of sequences, which gives sequences precedence over choices (like "*" has precedence over " " in math).
Both Choice and Sequence gather items in a temporary list. If this list contains only one item, then this item will be returned instead of a choice list or a sequence list.
You can test this parser like this:
const string example = "{{Hello,Hi,Hey} {world,earth},{Goodbye,farewell} {planet,rock,globe{.,!}}}";
var parser = new Parser();
var tree = parser.Parse(example);
for (int i = 0; i < 20; i ) {
Console.WriteLine(tree.GetRandomSentence());
}
The output might look like this:
再見搖滾
嗨地球
再見地球。
嘿世界
再見搖滾
嗨地球
嘿地球
告別地球
再見地球。
嘿世界
再見星球
你好世界
你好世界
再見星球
嘿地球
告別地球!
再見地球。
再見地球。
再見星球
告別搖滾
uj5u.com熱心網友回復:
我認為這可能是一項復雜的作業,因為我使用了本教程,因此我強烈建議您閱讀整個頁面以了解其作業原理。
首先,您必須將此“樹”作為陣列傳遞。您可以決議字串,手動設定陣列或其他任何內容。這很重要,因為該樹模型沒有好的模型,所以最好使用已經可用的模型。此外,重要的是,如果您想設定正確的語法,您需要為這些單詞添加“權重”,并告訴代碼如何正確設定以及以什么順序設定。
這是代碼片段:
using System;
using System.Text;
namespace App
{
class Program
{
static void Main(string[] args)
{
string tree = "{{Hello,Hi,Hey} {world,earth},{Goodbye,farewell} {planet,rock,globe{.,!}}}";
string[] words = { "Hello", "Hi", "Hey", "world", "earth", "Goodbye", "farewell", "planet", "rock", "globe" };
RandomText text = new RandomText(words);
text.AddContentParagraphs(12, 1, 3, 3, 3);
string content = text.Content;
Console.WriteLine(content);
}
}
public class RandomText
{
static Random _random = new Random();
StringBuilder _builder;
string[] _words;
public RandomText(string[] words)
{
_builder = new StringBuilder();
_words = words;
}
public void AddContentParagraphs(int numberParagraphs, int minSentences,
int maxSentences, int minWords, int maxWords)
{
for (int i = 0; i < numberParagraphs; i )
{
AddParagraph(_random.Next(minSentences, maxSentences 1),
minWords, maxWords);
_builder.Append("\n\n");
}
}
void AddParagraph(int numberSentences, int minWords, int maxWords)
{
for (int i = 0; i < numberSentences; i )
{
int count = _random.Next(minWords, maxWords 1);
AddSentence(count);
}
}
void AddSentence(int numberWords)
{
StringBuilder b = new StringBuilder();
// Add n words together.
for (int i = 0; i < numberWords; i ) // Number of words
{
b.Append(_words[_random.Next(_words.Length)]).Append(" ");
}
string sentence = b.ToString().Trim() ". ";
// Uppercase sentence
sentence = char.ToUpper(sentence[0]) sentence.Substring(1);
// Add this sentence to the class
_builder.Append(sentence);
}
public string Content
{
get
{
return _builder.ToString();
}
}
}
}
uj5u.com熱心網友回復:
如果問題是如何決議文本。我想也許你可以使用堆疊來決議它。
"{{Hello,Hi,Hey} {world,earth},{Goodbye,farewell} {planet,rock,globe{.,!}}}"
基本上,當您讀取字符不是'}'時,您將字符壓入堆疊。當你得到一個 '}' 時,你會多次從堆疊中彈出,直到你到達一個 '{'。但它有更多的細節,因為你有一個規則 ',' OR。
決議就像堆疊計算一樣。這就是您處理方程括號的方式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/400693.html
下一篇:Java中的等價排序二叉樹
