diff --git a/src/System Application/App/Edit in Excel/src/EditinExcelImpl.Codeunit.al b/src/System Application/App/Edit in Excel/src/EditinExcelImpl.Codeunit.al index b1627d53ec..1bcd93fa6e 100644 --- a/src/System Application/App/Edit in Excel/src/EditinExcelImpl.Codeunit.al +++ b/src/System Application/App/Edit in Excel/src/EditinExcelImpl.Codeunit.al @@ -28,6 +28,7 @@ codeunit 1482 "Edit in Excel Impl." ExcelFileNameTxt: Text; XmlByteEncodingTok: Label '_x00%1_%2', Locked = true; XmlByteEncoding2Tok: Label '%1_x00%2_%3', Locked = true; + XmlByteEncoding3Tok: Label '%1_%2_%3', Locked = true; procedure EditPageInExcel(PageCaption: Text[240]; PageId: Integer; EditinExcelFilters: Codeunit "Edit in Excel Filters"; FileName: Text) var @@ -100,7 +101,7 @@ codeunit 1482 "Edit in Excel Impl." VarFieldRef := VarKeyRef.FieldIndex(KeyFieldNumber); if not AddedFields.Contains(VarFieldRef.Number) then begin // Make sure we don't add the same field twice - // Add missing key fields at the beginning + // Add missing key fields at the beginning EditinExcelWorkbook.InsertColumn(0, VarFieldRef.Caption, ExternalizeODataObjectName(VarFieldRef.Name)); AddedFields.Add(VarFieldRef.Number); end; @@ -204,6 +205,7 @@ codeunit 1482 "Edit in Excel Impl." StartStr: Text; EndStr: Text; ByteValue: DotNet Byte; + IsByteValueUnderscore: Dictionary of [Integer, Boolean]; begin ConvertedName := Name; @@ -227,16 +229,32 @@ codeunit 1482 "Edit in Excel Impl." // Notice in the following line that – (en dash) is not a normal dash (em dash). // We need to handle this here because at least the norwegian translation uses en dash. if ConvertedName[CurrentPosition] in ['''', '+', '–'] then begin - ByteValue := Convert.ToByte(ConvertedName[CurrentPosition]); - StartStr := CopyStr(ConvertedName, 1, CurrentPosition - 1); - EndStr := CopyStr(ConvertedName, CurrentPosition + 1); - ConvertedName := StrSubstNo(XmlByteEncoding2Tok, StartStr, Convert.ToString(ByteValue, 16), EndStr); + if ConvertedName[CurrentPosition] in ['–'] then begin + StartStr := CopyStr(ConvertedName, 1, CurrentPosition - 1); + EndStr := CopyStr(ConvertedName, CurrentPosition + 1); + // TODO: Have a look at these edge cases around spaces, + // make it behave like the other code we have. + ConvertedName := StrSubstNo(XmlByteEncoding3Tok, StartStr, 'x2013', EndStr); + // length of _x00nn_ minus one that will be added later + end else begin + ByteValue := Convert.ToByte(ConvertedName[CurrentPosition]); + StartStr := CopyStr(ConvertedName, 1, CurrentPosition - 1); + EndStr := CopyStr(ConvertedName, CurrentPosition + 1); + ConvertedName := StrSubstNo(XmlByteEncoding2Tok, StartStr, Convert.ToString(ByteValue, 16), EndStr); + end; // length of _x00nn_ minus one that will be added later CurrentPosition += 6; + + IsByteValueUnderscore.Add(CurrentPosition, true); end else if ConvertedName[CurrentPosition] in [' ', '\', '/', '"', '.', '(', ')', '-', ':'] then if CurrentPosition > 1 then begin - if ConvertedName[CurrentPosition - 1] = '_' then begin + // The only cases where we allow 2 underscores in succession is when + // we have substituted a symbol with its byte value and when we have an actual underscore + // prefixed with a symbol that should be replaced with underscore. + // This code below removes duplicate underscores but + // needs to not remove underscores that was added via a byte value. + if (ConvertedName[CurrentPosition - 1] = '_') and not IsByteValueUnderscore.ContainsKey(CurrentPosition - 1) then begin ConvertedName := DelStr(ConvertedName, CurrentPosition, 1); CurrentPosition -= 1; end else diff --git a/src/System Application/Test/Edit in Excel/src/EditInExcelTest.Codeunit.al b/src/System Application/Test/Edit in Excel/src/EditInExcelTest.Codeunit.al index 77aa4dd6f0..28ef7e7f19 100644 --- a/src/System Application/Test/Edit in Excel/src/EditInExcelTest.Codeunit.al +++ b/src/System Application/Test/Edit in Excel/src/EditInExcelTest.Codeunit.al @@ -101,18 +101,56 @@ codeunit 132525 "Edit in Excel Test" RegularFieldName: Text; FieldNameStartingWDigit: Text; EnDashFieldName: Text; + EnDashFieldName2: Text; + EnDashFieldName3: Text; + EnDashFieldName4: Text; + ForwardSlashesFieldName: Text; + ManyForwardSlashesFieldName: Text; + ForwardSlashesAndUnderscoresFieldName: Text; begin Init(); FieldNameStartingWDigit := EditinExcelTestLibrary.ExternalizeODataObjectName('3field'); RegularFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('field'); ApostropheFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('new vendor''s name'); PlusFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('c+c field'); + + // Both spaces will be converted to underscore and the `en dash` will be converted to _x2013_ EnDashFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('lager – reklassfication field'); + + // The special symbol `en dash` will be converted to _x2013_ and the first prefixed space will be a converted + // to an underscore. + EnDashFieldName2 := EditinExcelTestLibrary.ExternalizeODataObjectName('lager –reklassfication field'); + + // The special symbol `en dash` will be converted to _x2013_ and the space will be a converted + // to an underscore. + EnDashFieldName3 := EditinExcelTestLibrary.ExternalizeODataObjectName('lager–reklassfication field'); + + // The two forward slashes will be converted to underscores and the `en dash` will be converted to _x2013_. + EnDashFieldName4 := EditinExcelTestLibrary.ExternalizeODataObjectName('lager/–/reklassfication field'); + + // Two forward slashes will have the first replaced with an underscore and the next removed. + ForwardSlashesFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('lager//reklassfication field'); + + // When we have a lot of forward slashes it only replaces the first one with an underscore and the rest + // are truncated. + ManyForwardSlashesFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('lager////////reklassfication field'); + + // The first forward slash will be converted to an underscore, the next underscore does not hit any + // special case so just stays as an underscore, the next forward slash follows the rule of not allowing + // two underscores when converting from a special symbol to underscore. + ForwardSlashesAndUnderscoresFieldName := EditinExcelTestLibrary.ExternalizeODataObjectName('lager/_/-reklassfication field'); + LibraryAssert.AreEqual('field', RegularFieldName, 'Conversion alters name that does not begin with a string'); LibraryAssert.AreEqual('_x0033_field', FieldNameStartingWDigit, 'Did not convert the name with number correctly'); LibraryAssert.AreEqual('new_vendor_x0027_s_name', ApostropheFieldName, 'Did not convert the name with an apostrophe correctly'); LibraryAssert.AreEqual('c_x002b_c_field', PlusFieldName, 'Did not convert the name with a plus correctly'); - LibraryAssert.AreEqual('lager__x2013__reklassfication_field', EnDashFieldName, 'Did not convert the name with an `en dash` correctly'); + LibraryAssert.AreEqual('lager__x2013__reklassfication_field', EnDashFieldName, 'Did not convert the name with an `en dash` with two surrounding spaces correctly'); + LibraryAssert.AreEqual('lager__x2013_reklassfication_field', EnDashFieldName2, 'Did not convert the name with a space before an `en dash` correctly'); + LibraryAssert.AreEqual('lager_x2013_reklassfication_field', EnDashFieldName3, 'Did not convert the name with an `en dash` correctly'); + LibraryAssert.AreEqual('lager__x2013__reklassfication_field', EnDashFieldName4, 'Did not convert the name with forward slashes around `en dash` correctly'); + LibraryAssert.AreEqual('lager_reklassfication_field', ForwardSlashesFieldName, 'Did not convert the name with 2 forward slashes correctly'); + LibraryAssert.AreEqual('lager_reklassfication_field', ManyForwardSlashesFieldName, 'Did not convert the name with many forward slashes correctly'); + LibraryAssert.AreEqual('lager__reklassfication_field', ForwardSlashesAndUnderscoresFieldName, 'Did not convert the name with '); end; [Test]