使用 Sprache 解析文本时,我可以确定原始字符串中的当前索引吗?
While parsing text using Sprache, can I determine the current index within the original string?
我设置了 Sprache 来解析一个方程式,其中有许多不同的可能方法调用。解析方法后,有没有办法确定原始字符串中的索引值?也许 Parse 有一个 "current index" 值和 "length" 值可以以某种方式访问?
示例输入字符串:
IndexOf("fred", 2) + IndexOf("bob")
使用这样的解析器...
Parser<Expression> FunctionCall = from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select CallMethod(namePart, Enumerable.Repeat(sourceData, 1)
.Concat(expr)
.ToArray());
谁能想出一个 "trick" 让我确定第一个 CallMethod 处理 SubString(0, 18),第二个 CallMethod 处理 SubString(21, 14) 来自原始字符串?
我已经设法回答了我自己的问题。 Positioned() 解析器扩展调用允许解析器跟踪原始文本中的位置。
Parser<Expression> FunctionCall = (from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select new MethodPosAware(namePart, expr)).Positioned()
.Select(x => CallMethod(x.Value, Enumerable.Repeat(sourceData, 1)
.Concat(x.Params)
.ToArray(),
x.Pos.Pos, x.Length));
我必须制作一个新的 MethodPosAware class 来保留位置信息,该信息源自 Sprache 的 IPositionAware:
class MethodPosAware : IPositionAware<MethodPosAware>
{
public MethodPosAware(string methodName, IEnumerable<Expression> parameters)
{
Value = methodName;
Params = parameters;
}
public MethodPosAware SetPos(Position startPos, int length)
{
Pos = startPos;
Length = length;
return this;
}
public Position Pos { get; set; }
public int Length { get; set; }
public string Value { get; set; }
public IEnumerable<Expression> Params { get; set; }
}
我想我会进一步扩展它以使用不仅仅是方法名称,但这足以回答我现在的问题。我希望这对以后的人有所帮助。
如果您使用通用 class 和扩展方法,您可以采用更通用的方法
public class PositionAware<T> : IPositionAware<PositionAware<T>>
{
public PositionAware(T value)
{
Value = value;
}
public T Value { get; }
public Position Start { get; private set; }
public int Length { get; private set; }
public PositionAware<T> SetPos(Position startPos, int length)
{
Start = startPos;
Length = length;
return this;
}
}
public static Parser<PositionAware<T>> WithPosition<T>(this Parser<T> value)
{
return value.Select(x => new PositionAware<T>(x)).Positioned();
}
使用它:
from c in Parse.Char('a').WithPosition()
select (c.Start, c.Value)
from c in Parameter.DelimitedBy(ListDelimiter).WithPosition()
select (c.Start, c.Value)
我设置了 Sprache 来解析一个方程式,其中有许多不同的可能方法调用。解析方法后,有没有办法确定原始字符串中的索引值?也许 Parse 有一个 "current index" 值和 "length" 值可以以某种方式访问?
示例输入字符串:
IndexOf("fred", 2) + IndexOf("bob")
使用这样的解析器...
Parser<Expression> FunctionCall = from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select CallMethod(namePart, Enumerable.Repeat(sourceData, 1)
.Concat(expr)
.ToArray());
谁能想出一个 "trick" 让我确定第一个 CallMethod 处理 SubString(0, 18),第二个 CallMethod 处理 SubString(21, 14) 来自原始字符串?
我已经设法回答了我自己的问题。 Positioned() 解析器扩展调用允许解析器跟踪原始文本中的位置。
Parser<Expression> FunctionCall = (from namePart in Parse.Letter.Many().Text()
from lparen in Parse.Char('(')
from expr in Parameter.DelimitedBy(ListDelimiter)
from rparen in Parse.Char(')')
select new MethodPosAware(namePart, expr)).Positioned()
.Select(x => CallMethod(x.Value, Enumerable.Repeat(sourceData, 1)
.Concat(x.Params)
.ToArray(),
x.Pos.Pos, x.Length));
我必须制作一个新的 MethodPosAware class 来保留位置信息,该信息源自 Sprache 的 IPositionAware:
class MethodPosAware : IPositionAware<MethodPosAware>
{
public MethodPosAware(string methodName, IEnumerable<Expression> parameters)
{
Value = methodName;
Params = parameters;
}
public MethodPosAware SetPos(Position startPos, int length)
{
Pos = startPos;
Length = length;
return this;
}
public Position Pos { get; set; }
public int Length { get; set; }
public string Value { get; set; }
public IEnumerable<Expression> Params { get; set; }
}
我想我会进一步扩展它以使用不仅仅是方法名称,但这足以回答我现在的问题。我希望这对以后的人有所帮助。
如果您使用通用 class 和扩展方法,您可以采用更通用的方法
public class PositionAware<T> : IPositionAware<PositionAware<T>>
{
public PositionAware(T value)
{
Value = value;
}
public T Value { get; }
public Position Start { get; private set; }
public int Length { get; private set; }
public PositionAware<T> SetPos(Position startPos, int length)
{
Start = startPos;
Length = length;
return this;
}
}
public static Parser<PositionAware<T>> WithPosition<T>(this Parser<T> value)
{
return value.Select(x => new PositionAware<T>(x)).Positioned();
}
使用它:
from c in Parse.Char('a').WithPosition()
select (c.Start, c.Value)
from c in Parameter.DelimitedBy(ListDelimiter).WithPosition()
select (c.Start, c.Value)