superpower - Superpower Parser:处理组合器中子解析器的部分匹配?
问题描述
所以我为专有文件类型编写了一个解析器。我在那里 95%,但我的解析器在文件的最后一行失败,即#
. 这是其他几个解析器的部分匹配。看起来它试图将行解析为 PropertyList 并失败,从而导致整个解析器失败。
我能做些什么来解决这个问题?
mcve 如下,Fiddle 在这里https://dotnetfiddle.net/f30sN9
using System;
using Superpower;
using Superpower.Model;
using Superpower.Parsers;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var result1 = TagTXTParser.firstLine.TryParse(sampleFirstLine);
Console.WriteLine(result1);
var result2 = TagTXTParser.propertyList.TryParse(samplePropertyList);
Console.WriteLine(result2);
var result8 = TagTXTParser.record.TryParse(sampleRecord);
Console.WriteLine(result8);
var result9 = TagTXTParser.TagRecordsFileParser.TryParse(sampleFile);
Console.WriteLine(result9);
}
public static string sampleFirstLine = "// 895.34 - Tags\n";
public static string sampleSectionHeading = "#Parameters\n";
public static string sampleItemList = "<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |\n";
public static string samplePropertyList = "#4|NavDisabled|0|1| | |0|0| |\n";
public static string sampleSection1 = "#Parameters\n<[0] >| 1 | 0 | 0 | 0 | 0 | 0.000000 | 0.000000 | 0.000000 | | | | \n";
public static string sampleSection2 = "#Parameters\n<[0] >| 1 | 0 | 0 | 0 | 0 | 0.000000 | 0.000000 | 0.000000 | | | | \n<[1] >| 1 | 0 | 0 | 0 | 0 | 0.000000 | 0.000000 | 0.000000 | | | | \n";
public static string sampleSection3 = "#Parameters\n";
public static string sampleRecord = "#3|ScreenNumber|0|1| | |1|0| |\n#Parameters\n<[0] >| 1 | 0 | 0 | 0 | 0 | 0.000000 | 0.000000 | 0.000000 | | | |\n#Alarm\n#History\n#ItemParameters\n<[0] >| 1 | 1 | \n";
public static string sampleFile =
@"// 8.10 - Application Tags
#1|SelectedWindowOnNavBar|0|1| | |1|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#2|ScreenName|0|3| | |1|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#3|ScreenNumber|0|1| | |1|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#4|NavDisabled|0|1| | |0|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#5|PLC_1_IPAddress|0|3| | |1|0| |
#Parameters
<[0]>|1|1|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#6|NumOfMeters|0|3| | |1|0| |
#Parameters
<[0]>|1|1|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#7|ComputerName|0|3| | |1|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#8|TZPosition|0|1| | |0|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#9|NewTime|0|3| | |1|0| |
#Parameters
<[0]>|1|0|0|0|0|0.000000|0.000000|0.000000| | | |
#Alarm
#History
#ItemParameters
<[0]>|1|1|
#";
}
public class TagTXTParser
{
public record TagProperies(int Id, string Name, List<string> others);
public record TagRecordSection(List<string>[] items);
public class TagRecord
{
public int Id { get; set; } //** first element of First line
public string Name { get; set; }
public List<string> Properties { get; set; }
public TagRecordSection Parameters { get; set; }
public TagRecordSection Alarm { get; set; }
public TagRecordSection History { get; set; }
public TagRecordSection ItemParameters { get; set; }
}
public static TextParser<char> hash = Character.EqualTo('#');
public static TextParser<TextSpan> eol = Span.EqualTo('\n').Or(Span.EqualTo("\r\n"));
public static TextParser<char> pipe = Character.EqualTo('|');
public static TextParser<string> text = Character.ExceptIn('#', '|', '\n', '\r').Many().Select(x => new string(x));
public static TextParser<string> firstLine = from _ in Span.EqualTo("//")
from rest in text
from end in eol
select new string(rest.ToCharArray());
public static TextParser<char[]> heading =
from h in hash
from name in Character.Letter.AtLeastOnce()
from end in eol
select name;
public static TextParser<List<string>> itemList = //from _ in eol
from items in text.ManyDelimitedBy<string, char>(pipe)
from end in eol
select new List<string>(items);
public static TextParser<TagProperies> propertyList =
from _ in hash
from id in Character.Digit.AtLeastOnce()
from endOfId in pipe
from name in text
from endOfName in pipe
from otherItems in itemList
select new TagProperies(Convert.ToInt32(new string(id)), name, otherItems);
public static TextParser<TagRecordSection> section =
from _ in heading
from items in itemList.Many()
select new TagRecordSection(items);
public static TextParser<TagRecord> record =
from props in propertyList
from sections in section.Repeat(4)
select new TagRecord()
{
Id = props.Id,
Name = props.Name,
Properties = props.others,
Parameters = sections[0],
Alarm = sections[1],
History = sections[2],
ItemParameters = sections[3]
};
public static TextParser<TagRecord[]> TagRecordsFileParser =
from _ in firstLine
from records in record.Many()
from end in hash
select records;
}
解决方案
您需要.Try()
在您的TagRecordsFileParser
:
public static TextParser<TagRecord[]> TagRecordsFileParser =
from _ in firstLine
from records in record.Try().Many() // <--- HERE
from end in hash
select records;
原因是当你打电话时record.Many()
,它会检查你的 9 条记录,然后看到另一个哈希,所以它认为它是另一个record
。解析器“消耗”散列,但结果证明它根本不是记录,这导致它失败。调用record.Try().Many()
告诉 Superpower 尝试解析尽可能多record
的 ',但如果一个失败,不要让整个解析器失败,只需回溯已经消耗的任何内容,然后继续解析器定义的其余部分。
您必须做的另一件事是.AtEnd()
在解析输入时添加调用:
var result9 = TagTXTParser.TagRecordsFileParser.AtEnd().TryParse(sampleFile);
这样,解析器只有在成功解析您的整个输入时才会成功。这将使您的输入始终以单个#
字符结尾。#x
否则没有这个,如果文件以我认为你不想要的东西结尾,解析器就会成功。
推荐阅读
- javascript - 在 JavaScript 中仅解析 JSON API 的一部分
- php - PHP JSON编码缺少对象的问题
- python - Parse JSOn multiple objects to CSV
- r - Problems parsing StreamR JSON data
- sql-server - 从给定列中获取客户年龄(以月为单位)(SQL Server 2017)
- php - 我不知道“.com/?c=f25a9a5f951d”是什么意思
- apache-spark - 如何在 pyspark 中为令牌特征数组维护单词到索引映射的顺序?
- c++ - Beckhoff 如何在 CycleUpdate 中使用 TWINCAT 3 C++ 打开和读取文件?
- python - 无法格式化 JSON 数据
- android - Android 动画旋转可绘制:官方文档在哪里?