Skip to content

Commit

Permalink
Introduced new EscapeCharacters and AddEscapeCharacter() options on…
Browse files Browse the repository at this point in the history
… the edi grammar. It is used by the EdiTextWriter to escape additional characters inside values #160.
  • Loading branch information
cleftheris committed Jul 6, 2020
1 parent 60000ff commit 034e9e8
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 24 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1.9.9.{build}
version: 1.9.10.{build}
image: Visual Studio 2019
configuration: Release
platform: Any CPU
Expand Down
18 changes: 18 additions & 0 deletions src/indice.Edi/EdiGrammar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ private char[] Separators {
/// <value>An array of possible characters</value>
public char[] Reserved { get; protected set; }

/// <summary>
/// <para>
/// These characters will be escaped by the serializer. This list should only include non default (additional) characters to be escaped.
/// </para>
/// </summary>
/// <value>An array of additioal escape characters.</value>
public string EscapeCharacters { get; protected set; }

/// <summary>
/// Segment terminator indicates the end of a message segment.
/// </summary>
Expand Down Expand Up @@ -200,6 +208,16 @@ public void SetAdvice(char segmentNameDelimiter,
_separators = null;
}

/// <summary>
/// Adds an character to the list of escape chars.
/// </summary>
/// <param name="characterToEscape">The character to escape</param>
public void AddEscapeCharacter(char characterToEscape) {
if (EscapeCharacters == null)
EscapeCharacters = string.Empty;
EscapeCharacters += characterToEscape;
}

/// <summary>
/// Factory for creating an <see cref="IEdiGrammar"/> with the EdiFact defaults.
/// </summary>
Expand Down
12 changes: 8 additions & 4 deletions src/indice.Edi/EdiTextWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public EdiTextWriter(TextWriter textWriter, IEdiGrammar grammar)
_charEscapeFlags[Grammar.SegmentNameDelimiter] =
_charEscapeFlags[Grammar.SegmentTerminator] =
_charEscapeFlags[Grammar.ReleaseCharacter.Value] = true;
if (Grammar.EscapeCharacters != null)
foreach (var c in Grammar.EscapeCharacters) {
_charEscapeFlags[c] = true;
}
}
}

Expand Down Expand Up @@ -301,7 +305,7 @@ public override void WriteValue(ulong value, Picture? picture = null) {
/// <param name="picture"></param>
public override void WriteValue(float value, Picture? picture) {
InternalWriteValue(EdiToken.Float);
_writer.Write(value.ToEdiString(picture, Grammar.DecimalMark));
WriteEscapedString(value.ToEdiString(picture, Grammar.DecimalMark));
}

/// <summary>
Expand All @@ -314,7 +318,7 @@ public override void WriteValue(float? value, Picture? picture = null) {
WriteNull();
} else {
InternalWriteValue(EdiToken.Float);
_writer.Write(value.ToEdiString(picture, Grammar.DecimalMark));
WriteEscapedString(value.ToEdiString(picture, Grammar.DecimalMark));
}
}

Expand All @@ -325,7 +329,7 @@ public override void WriteValue(float? value, Picture? picture = null) {
/// <param name="picture"></param>
public override void WriteValue(double value, Picture? picture = null) {
InternalWriteValue(EdiToken.Float);
_writer.Write(value.ToEdiString(picture, Grammar.DecimalMark));
WriteEscapedString(value.ToEdiString(picture, Grammar.DecimalMark));
}

/// <summary>
Expand All @@ -338,7 +342,7 @@ public override void WriteValue(double? value, Picture? picture = null) {
WriteNull();
} else {
InternalWriteValue(EdiToken.Float);
_writer.Write(value.ToEdiString(picture, Grammar.DecimalMark));
WriteEscapedString(value.ToEdiString(picture, Grammar.DecimalMark));
}
}

Expand Down
18 changes: 16 additions & 2 deletions src/indice.Edi/IEdiGrammar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ public interface IEdiGrammar
/// <value>An array of possible characters</value>
char[] Reserved { get; }

/// <summary>
/// <para>
/// These characters will be escaped by the serializer. This list should only include non default (additional) characters to be escaped.
/// </para>
/// </summary>
/// <value>An array of additioal escape characters.</value>
string EscapeCharacters { get; }

/// <summary>
/// Segment terminator indicates the end of a message segment.
/// </summary>
Expand Down Expand Up @@ -75,7 +83,7 @@ public interface IEdiGrammar
/// The segment name that marks the Message Trailer.
/// </summary>
string MessageTrailerTag { get; }

/// <summary>
/// The segment name that marks the Functional Group Trailer.
/// </summary>
Expand Down Expand Up @@ -111,10 +119,16 @@ public interface IEdiGrammar
/// <param name="decimalMark">populates <see cref="DecimalMark"/> character</param>
void SetAdvice(char segmentNameDelimiter,
char dataElementSeparator,
char componentDataElementSeparator,
char componentDataElementSeparator,
char segmentTerminator,
char? releaseCharacter,
char? reserved,
char? decimalMark);

/// <summary>
/// Adds an character to the list of escape chars.
/// </summary>
/// <param name="characterToEscape">The character to escape</param>
void AddEscapeCharacter(char characterToEscape);
}
}
25 changes: 18 additions & 7 deletions src/indice.Edi/Utilities/EdiExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,19 +311,30 @@ public static string ToEdiString(this decimal? value, Picture? picture, char? de
if (!value.HasValue)
return null;
var provider = NumberFormatInfo.InvariantInfo;
if (picture.HasValue && picture.Value.Kind == PictureKind.Numeric && picture.Value.HasPrecision) {
if (decimalMark.HasValue) {
if (provider.NumberDecimalSeparator != decimalMark.ToString()) {
provider = provider.Clone() as NumberFormatInfo;
provider.NumberDecimalSeparator = decimalMark.Value.ToString();
}
if (picture.HasValue && picture.Value.Kind == PictureKind.Numeric && picture.Value.HasPrecision) {
var integerMask = new string(Enumerable.Range(0, picture.Value.Scale - picture.Value.Precision).Select(i => '0').ToArray());
if (integerMask.Length == 0) {
integerMask = "#";
}
var precisionMask = new string(Enumerable.Range(0, picture.Value.Precision).Select(i => '0').ToArray());
if (precisionMask.Length == 0) {
precisionMask = "#";
}
return value.Value.ToString($"{integerMask}.{precisionMask}", provider);
}
return value.Value.ToString(provider);
} else if (picture.HasValue && picture.Value.Kind == PictureKind.Numeric && picture.Value.HasPrecision) {
var pic = picture.Value;
var number = value.Value;
var integer = (int)(number * (decimal)Math.Pow(10.0, pic.Precision));
var padding = new string(Enumerable.Range(0, pic.Scale).Select(i => '0').ToArray());
var result = integer.ToString(padding);
return result;
} else if (decimalMark.HasValue) {
if (provider.NumberDecimalSeparator != decimalMark.ToString()) {
provider = provider.Clone() as NumberFormatInfo;
provider.NumberDecimalSeparator = decimalMark.Value.ToString();
}
return value.Value.ToString(provider);
} else if (picture.HasValue && picture.Value.Kind == PictureKind.Numeric) {
var pic = picture.Value;
var number = value.Value;
Expand Down
3 changes: 2 additions & 1 deletion src/indice.Edi/indice.Edi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<Description>Edi.Net Class Library</Description>
<Copyright>Copyright (c) 2015 Indice</Copyright>
<AssemblyTitle>Edi.Net</AssemblyTitle>
<VersionPrefix>1.9.9</VersionPrefix>
<VersionPrefix>1.9.10</VersionPrefix>
<!--<VersionSuffix>beta1</VersionSuffix>-->
<Authors>c.leftheris</Authors>
<TargetFrameworks>net40;net45;netstandard1.0;netstandard1.3;netstandard2.0</TargetFrameworks>
Expand All @@ -23,6 +23,7 @@
- Fixed EdiSerializer bug when using Serialize overload that passes a plain `TextWriter` the internal EdiTextWriter was never closed thus not autocompleteing/terminating the current active structure #142.
- Fixed EdiReader when empty segment was found without segment name delimiter #152.
- Introduced new `SuppressBadEscapeSequenceErrors` option on the serializer. it is used to suppress the exception error thrown when a malformed escape sequence is encountered #157.
- Introduced new `EscapeCharacters` and AddEscapeCharacter() options on the edi grammar. It is used by the EdiTextWriter to escape additional characters inside values #160.
</PackageReleaseNotes>
<PackageIcon>icon-256.png</PackageIcon>
<PackageProjectUrl>https://github.com/indice-co/EDI.Net</PackageProjectUrl>
Expand Down
17 changes: 17 additions & 0 deletions test/indice.Edi.Tests/EdiTextWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,22 @@ public void WriterWrites_Boolean_Correctly() {
}
Assert.Equal(expected.ToString(), output.ToString());
}

[Fact, Trait(Traits.Tag, "Writer"), Trait(Traits.Issue, "#160")]
public void WriterWrites_Precision_Correctly() {
var grammar = EdiGrammar.NewEdiFact();
grammar.SetAdvice('+', '+', ':', '\'', '?', null, ',');
grammar.AddEscapeCharacter(',');
var expected = new StringBuilder().Append($"AAA+10?,42+:234?,46'{Environment.NewLine}");
var output = new StringBuilder();
using (var writer = new EdiTextWriter(new StringWriter(output), grammar)) {
writer.WriteToken(EdiToken.SegmentName, "AAA"); Assert.Equal("AAA", writer.Path);
writer.WriteValue(10.42345, (Picture)"9(1)V9(2)"); Assert.Equal("AAA[0][0]", writer.Path);
writer.WriteToken(EdiToken.ElementStart); Assert.Equal("AAA[1]", writer.Path);
writer.WriteToken(EdiToken.Null); Assert.Equal("AAA[1][0]", writer.Path);
writer.WriteValue(234.45563, (Picture)"9(1)V9(2)"); Assert.Equal("AAA[1][1]", writer.Path);
}
Assert.Equal(expected.ToString(), output.ToString());
}
}
}
29 changes: 20 additions & 9 deletions test/indice.Edi.Tests/ToEdiStringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,27 @@ namespace indice.Edi.Tests
{
public class ToEdiStringTests
{
[Fact]
[Trait(Traits.Tag, "Parser")]
public void IntegerToStringTest() {
Assert.Equal(" 12", EdiExtensions.ToEdiString(12, (Picture)"X(5)"));
Assert.Equal("00012", EdiExtensions.ToEdiString(12, (Picture)"9(5)"));
Assert.Equal("00012", EdiExtensions.ToEdiString(12, (Picture)"9(5)"));
Assert.Equal("12", EdiExtensions.ToEdiString(12, (Picture)"X(1)"));
Assert.Equal("12", EdiExtensions.ToEdiString(12, (Picture)"9(1)"));

Assert.Equal("29012", EdiExtensions.ToEdiString(290.12M, (Picture)"9(3)V9(2)", '.'));
[Theory]
[InlineData(" 12", 12, "X(5)")]
[InlineData("00012", 12, "9(5)")]
[InlineData("12", 12, "X(1)")]
[InlineData("12", 12, "9(1)")]
public void IntegerToStringTest(string expectedValue, int value, string picture) {
Assert.Equal(expectedValue, EdiExtensions.ToEdiString(value, (Picture)picture));
}

[Trait(Traits.Tag, "Parser")]
[Theory]
[InlineData("29012", 290.12, "9(3)V9(2)", null)]
[InlineData("290.12", 290.12, "9(3)V9(2)", '.')]
[InlineData("0290.12", 290.12, "9(4)V9(2)", '.')]
[InlineData("0001,03", 1.028, "9(4)V9(2)", ',')]
[InlineData("0,03", 0.028, "9(1)V9(2)", ',')]
[InlineData("21,03", 21.03, "9(1)V9(2)", ',')]
[InlineData(",03", 0.028, "9(0)V9(2)", ',')]
public void FloatToStringTest(string expectedValue, decimal value, string picture, char? decimalMark) {
Assert.Equal(expectedValue, EdiExtensions.ToEdiString(value, (Picture)picture, decimalMark));
}
}
}

0 comments on commit 034e9e8

Please sign in to comment.