diff --git a/DbcParserLib.Tests/ValueTableLineParserTests.cs b/DbcParserLib.Tests/ValueTableLineParserTests.cs index 38366bd..bf38e64 100644 --- a/DbcParserLib.Tests/ValueTableLineParserTests.cs +++ b/DbcParserLib.Tests/ValueTableLineParserTests.cs @@ -182,6 +182,57 @@ public void ValueTableWithMapDefinitionIsParsedAndLinkedToChannel() Assert.IsTrue(ParseLine(@"VAL_ 470 channelName 3 ""AEB_LOCK_STATE_SNA"" 2 ""AEB_LOCK_STATE_UNUSED"" 1 ""AEB_LOCK_STATE_UNLOCKED"" 0 ""AEB_LOCK_STATE_LOCKED"" ;", valueTableLineParsers, dbcBuilderMock.Object, nextLineProviderMock.Object)); } + [TestCase("VAL_TABLE_ TableName 0 \"Running\" 1 \" Idle\" ;")] + [TestCase("VAL_TABLE_ TableName 0 \"Running\" 1 \" Idle \" ;")] + [TestCase("VAL_TABLE_ TableName 0 \"Running\" 1 \" \" ;")] + [TestCase("VAL_TABLE_ TableName 0 \"Running\" 1 \"\" ;")] + public void ValueTableDefinitionWithSpacesInValuesIsParsed(string line) + { + var dbcBuilderMock = m_repository.Create(); + var finalDict = new Dictionary(); + + dbcBuilderMock.Setup( + builder => builder.AddNamedValueTable( + "TableName", + It.IsAny>(), + It.IsAny() + )).Callback, string>((_, dict, _) => + { + finalDict = new Dictionary(dict); + }); + var valueTableLineParsers = CreateParser(); + var nextLineProviderMock = m_repository.Create(); + + Assert.IsTrue(ParseLine(line, valueTableLineParsers, dbcBuilderMock.Object, nextLineProviderMock.Object)); + Assert.AreEqual(2, finalDict.Count); + } + + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \" Idle\" ;")] + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \" Idle \" ;")] + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \" \" ;")] + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \"\" ;")] + public void ValueTableWithSpacesInValuesIsParsed(string line) + { + var dbcBuilderMock = m_repository.Create(); + var finalDict = new Dictionary(); + + dbcBuilderMock.Setup( + builder => builder.LinkTableValuesToSignal( + 869, + "qGearboxOil", + It.IsAny>(), + It.IsAny() + )).Callback, string>((_, _, dict, _) => + { + finalDict = new Dictionary(dict); + }); + var valueTableLineParsers = CreateParser(); + var nextLineProviderMock = m_repository.Create(); + + Assert.IsTrue(ParseLine(line, valueTableLineParsers, dbcBuilderMock.Object, nextLineProviderMock.Object)); + Assert.AreEqual(2, finalDict.Count); + } + [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \"Idle\" ")] [TestCase("VAL_ 869 qGearboxOil 0 \"Running\" 1 \"Idle\";")] [TestCase("VAL_ -869 qGearboxOil 0 \"Running\" 1 \"Idle\" ;")] diff --git a/DbcParserLib/ExtensionsAndHelpers.cs b/DbcParserLib/ExtensionsAndHelpers.cs index 0047e7e..8466063 100644 --- a/DbcParserLib/ExtensionsAndHelpers.cs +++ b/DbcParserLib/ExtensionsAndHelpers.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using System.Collections.Generic; +using System.Text.RegularExpressions; using DbcParserLib.Model; namespace DbcParserLib @@ -71,6 +72,7 @@ internal static void AdjustExtendedId(this Message message) internal static IReadOnlyDictionary ToDictionary(this string records) { + const string valueTableValueRegex = @"(-?\d+)\s+(""[^""]*"")"; var dict = new Dictionary(); if (string.IsNullOrWhiteSpace(records)) @@ -85,9 +87,9 @@ internal static IReadOnlyDictionary ToDictionary(this string record if (string.IsNullOrWhiteSpace(line)) continue; - // Add duplicated key control and act (eg. strict -> break, warning -> keep going and log, silent-> keep going) - var tokens = line.Split(' '); - dict[int.Parse(tokens[0])] = tokens[1]; + var match = Regex.Match(line, valueTableValueRegex); + if (match.Success) + dict[int.Parse(match.Groups[1].Value)] = match.Groups[2].Value; } } return dict; diff --git a/DbcParserLib/Helpers.cs b/DbcParserLib/Helpers.cs index 61030ea..c0b2466 100644 --- a/DbcParserLib/Helpers.cs +++ b/DbcParserLib/Helpers.cs @@ -19,7 +19,7 @@ public static string ConvertToMultiLine(string[] records, int offset) var sb = new StringBuilder(); for (var i = offset; i < records.Length - 1; i += 2) { - sb.AppendLine($"{records[i]} {records[i + 1]}"); + sb.AppendFormat("{0} {1} {2}", records[i], records[i+1], '\n'); } return sb.ToString(); diff --git a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs index 90f621a..e043be3 100644 --- a/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableDefinitionLineParser.cs @@ -1,5 +1,4 @@ -using System; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using DbcParserLib.Observers; namespace DbcParserLib.Parsers @@ -8,6 +7,8 @@ internal class ValueTableDefinitionLineParser : ILineParser { private const string ValueTableDefinitionLineStarter = "VAL_TABLE_ "; private const string ValueTableDefinitionParsingRegex = @"VAL_TABLE_\s+([a-zA-Z_][\w]*)\s+((?:\d+\s+(?:""[^""]*"")\s+)*)\s*;"; + private const string ValueTableNewLineRegex = @"(""[^""]*""\s+)"; + private const string ValueTableNewLineRegexReplace = "$1\n"; private readonly IParseFailureObserver m_observer; @@ -26,7 +27,7 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin var match = Regex.Match(cleanLine, ValueTableDefinitionParsingRegex); if (match.Success) { - var valueTable = match.Groups[2].Value.Replace("\" ", "\"" + Environment.NewLine); + var valueTable = Regex.Replace(match.Groups[2].Value.TrimStart(), ValueTableNewLineRegex, ValueTableNewLineRegexReplace); var valueTableDictionary = valueTable.ToDictionary(); builder.AddNamedValueTable(match.Groups[1].Value, valueTableDictionary, valueTable); } diff --git a/DbcParserLib/Parsers/ValueTableLineParser.cs b/DbcParserLib/Parsers/ValueTableLineParser.cs index dad1017..3859d41 100644 --- a/DbcParserLib/Parsers/ValueTableLineParser.cs +++ b/DbcParserLib/Parsers/ValueTableLineParser.cs @@ -1,4 +1,3 @@ -using System; using System.Text.RegularExpressions; using DbcParserLib.Observers; @@ -9,6 +8,8 @@ internal class ValueTableLineParser : ILineParser private const string ValueTableLineStarter = "VAL_ "; private const string ValueTableLinkParsingRegex = @"VAL_\s+(\d+)\s+([a-zA-Z_][\w]*)\s+([a-zA-Z_][\w]*)\s*;"; private const string ValueTableParsingRegex = @"VAL_\s+(?:(?:(\d+)\s+([a-zA-Z_][\w]*))|([a-zA-Z_][\w]*))\s+((?:(?:-?\d+)\s+(?:""[^""]*"")\s+)*)\s*;"; + private const string ValueTableNewLineRegex = @"(""[^""]*""\s+)"; + private const string ValueTableNewLineRegexReplace = "$1\n"; private readonly IParseFailureObserver m_observer; @@ -34,7 +35,7 @@ public bool TryParse(string line, IDbcBuilder builder, INextLineProvider nextLin match = Regex.Match(cleanLine, ValueTableParsingRegex); if (match.Success) { - var valueTable = match.Groups[4].Value.TrimStart().Replace("\" ", "\"" + Environment.NewLine); + var valueTable = Regex.Replace(match.Groups[4].Value.TrimStart(), ValueTableNewLineRegex, ValueTableNewLineRegexReplace); var valueTableDictionary = valueTable.ToDictionary(); if (match.Groups[3].Value != "") builder.LinkTableValuesToEnvironmentVariable(match.Groups[3].Value, valueTableDictionary);