implemented encoding format c, and support for customer information 3. i would do 2 as well but it's 0347. next up, unit testing for the first time in my stinchin life

This commit is contained in:
Lynne Megido 2020-10-14 03:47:33 +10:00
parent d290dbadad
commit a34702dc6c
Signed by: lynnesbian
GPG key ID: F0A184B5213D9F90
3 changed files with 161 additions and 80 deletions

View file

@ -22,7 +22,6 @@
<list default="true" id="373c5ee6-3f10-450b-8af6-fc4dd99290b0" name="Default Changelist" comment="initial commit, as they say"> <list default="true" id="373c5ee6-3f10-450b-8af6-fc4dd99290b0" name="Default Changelist" comment="initial commit, as they say">
<change beforePath="$PROJECT_DIR$/.idea/.idea.auspostcode.dir/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.auspostcode.dir/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.auspostcode.dir/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.auspostcode.dir/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Barcode.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Barcode.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Barcode.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Barcode.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/BaseConversion.cs" beforeDir="false" afterPath="$PROJECT_DIR$/BaseConversion.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Program.cs" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Program.cs" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
@ -45,6 +44,7 @@
<option value="$PROJECT_DIR$/BarcodeVersion.cs" /> <option value="$PROJECT_DIR$/BarcodeVersion.cs" />
<option value="$PROJECT_DIR$/.gitignore" /> <option value="$PROJECT_DIR$/.gitignore" />
<option value="$PROJECT_DIR$/BaseConversion.cs" /> <option value="$PROJECT_DIR$/BaseConversion.cs" />
<option value="$APPLICATION_CONFIG_DIR$/scratches/scratch.txt" />
<option value="$PROJECT_DIR$/Program.cs" /> <option value="$PROJECT_DIR$/Program.cs" />
<option value="$PROJECT_DIR$/Barcode.cs" /> <option value="$PROJECT_DIR$/Barcode.cs" />
</list> </list>
@ -65,6 +65,7 @@
<property name="WebServerToolWindowFactoryState" value="false" /> <property name="WebServerToolWindowFactoryState" value="false" />
<property name="XThreadsFramesViewSplitterKey" value="0.7161862" /> <property name="XThreadsFramesViewSplitterKey" value="0.7161862" />
<property name="add_unversioned_files" value="true" /> <property name="add_unversioned_files" value="true" />
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="TEXT" />
<property name="settings.editor.selected.configurable" value="preferences.sourceCode.C#" /> <property name="settings.editor.selected.configurable" value="preferences.sourceCode.C#" />
<property name="vue.rearranger.settings.migration" value="true" /> <property name="vue.rearranger.settings.migration" value="true" />
</component> </component>
@ -96,7 +97,7 @@
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1602593942454</updated> <updated>1602593942454</updated>
<workItem from="1602593947835" duration="13843000" /> <workItem from="1602593947835" duration="17273000" />
</task> </task>
<task id="LOCAL-00001" summary="initial commit, as they say"> <task id="LOCAL-00001" summary="initial commit, as they say">
<created>1602597326777</created> <created>1602597326777</created>
@ -148,86 +149,86 @@
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state x="727" y="366" width="424" height="478" key="FileChooserDialogImpl/0.0.1920.1054@0.0.1920.1054" timestamp="1602597073977" /> <state x="727" y="366" width="424" height="478" key="FileChooserDialogImpl/0.0.1920.1054@0.0.1920.1054" timestamp="1602597073977" />
<state width="1878" height="374" key="GridCell.Tab.0.bottom" timestamp="1602607646431"> <state width="1878" height="374" key="GridCell.Tab.0.bottom" timestamp="1602610374478">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.0.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646431" /> <state width="1878" height="374" key="GridCell.Tab.0.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374478" />
<state width="1878" height="374" key="GridCell.Tab.0.center" timestamp="1602607646431"> <state width="1878" height="374" key="GridCell.Tab.0.center" timestamp="1602610374477">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.0.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646431" /> <state width="1878" height="374" key="GridCell.Tab.0.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374477" />
<state width="1878" height="374" key="GridCell.Tab.0.left" timestamp="1602607646431"> <state width="1878" height="374" key="GridCell.Tab.0.left" timestamp="1602610374476">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.0.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646431" /> <state width="1878" height="374" key="GridCell.Tab.0.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374476" />
<state width="1878" height="374" key="GridCell.Tab.0.right" timestamp="1602607646431"> <state width="1878" height="374" key="GridCell.Tab.0.right" timestamp="1602610374478">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.0.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646431" /> <state width="1878" height="374" key="GridCell.Tab.0.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374478" />
<state width="1878" height="374" key="GridCell.Tab.1.bottom" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.1.bottom" timestamp="1602610374479">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.1.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.1.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374479" />
<state width="1878" height="374" key="GridCell.Tab.1.center" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.1.center" timestamp="1602610374479">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.1.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.1.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374479" />
<state width="1878" height="374" key="GridCell.Tab.1.left" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.1.left" timestamp="1602610374478">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.1.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.1.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374478" />
<state width="1878" height="374" key="GridCell.Tab.1.right" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.1.right" timestamp="1602610374479">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.1.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.1.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374479" />
<state width="1878" height="374" key="GridCell.Tab.2.bottom" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.2.bottom" timestamp="1602610374481">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.2.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.2.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374481" />
<state width="1878" height="374" key="GridCell.Tab.2.center" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.2.center" timestamp="1602610374480">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.2.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.2.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374480" />
<state width="1878" height="374" key="GridCell.Tab.2.left" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.2.left" timestamp="1602610374480">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.2.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.2.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374480" />
<state width="1878" height="374" key="GridCell.Tab.2.right" timestamp="1602607646287"> <state width="1878" height="374" key="GridCell.Tab.2.right" timestamp="1602610374480">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.2.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646287" /> <state width="1878" height="374" key="GridCell.Tab.2.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374480" />
<state width="1878" height="374" key="GridCell.Tab.3.bottom" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.3.bottom" timestamp="1602610374482">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.3.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.3.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374482" />
<state width="1878" height="374" key="GridCell.Tab.3.center" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.3.center" timestamp="1602610374482">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.3.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.3.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374482" />
<state width="1878" height="374" key="GridCell.Tab.3.left" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.3.left" timestamp="1602610374481">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.3.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.3.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374481" />
<state width="1878" height="374" key="GridCell.Tab.3.right" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.3.right" timestamp="1602610374482">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.3.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.3.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374482" />
<state width="1878" height="374" key="GridCell.Tab.4.bottom" timestamp="1602607646289"> <state width="1878" height="374" key="GridCell.Tab.4.bottom" timestamp="1602610374484">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.4.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646289" /> <state width="1878" height="374" key="GridCell.Tab.4.bottom/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374484" />
<state width="1878" height="374" key="GridCell.Tab.4.center" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.4.center" timestamp="1602610374483">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.4.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.4.center/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374483" />
<state width="1878" height="374" key="GridCell.Tab.4.left" timestamp="1602607646288"> <state width="1878" height="374" key="GridCell.Tab.4.left" timestamp="1602610374483">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.4.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646288" /> <state width="1878" height="374" key="GridCell.Tab.4.left/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374483" />
<state width="1878" height="374" key="GridCell.Tab.4.right" timestamp="1602607646289"> <state width="1878" height="374" key="GridCell.Tab.4.right" timestamp="1602610374484">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state width="1878" height="374" key="GridCell.Tab.4.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602607646289" /> <state width="1878" height="374" key="GridCell.Tab.4.right/0.0.1920.1054@0.0.1920.1054" timestamp="1602610374484" />
<state x="738" y="92" key="SettingsEditor" timestamp="1602603890848"> <state x="738" y="92" key="SettingsEditor" timestamp="1602603890848">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
@ -240,6 +241,10 @@
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state x="100" y="99" width="1720" height="855" key="com.intellij.history.integration.ui.views.DirectoryHistoryDialog/0.0.1920.1054@0.0.1920.1054" timestamp="1602597391150" /> <state x="100" y="99" width="1720" height="855" key="com.intellij.history.integration.ui.views.DirectoryHistoryDialog/0.0.1920.1054@0.0.1920.1054" timestamp="1602597391150" />
<state x="482" y="127" width="945" height="793" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser" timestamp="1602607983699">
<screen x="0" y="0" width="1920" height="1054" />
</state>
<state x="482" y="127" width="945" height="793" key="com.intellij.openapi.editor.actions.MultiplePasteAction$ClipboardContentChooser/0.0.1920.1054@0.0.1920.1054" timestamp="1602607983699" />
<state x="623" y="270" width="673" height="512" key="find.popup" timestamp="1602599001638"> <state x="623" y="270" width="673" height="512" key="find.popup" timestamp="1602599001638">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
@ -248,9 +253,9 @@
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state x="440" y="285" width="1009" height="647" key="org.intellij.images.editor.actions.BackgroundImageDialog/0.0.1920.1054@0.0.1920.1054" timestamp="1602598923528" /> <state x="440" y="285" width="1009" height="647" key="org.intellij.images.editor.actions.BackgroundImageDialog/0.0.1920.1054@0.0.1920.1054" timestamp="1602598923528" />
<state x="623" y="231" width="672" height="678" key="search.everywhere.popup" timestamp="1602599024210"> <state x="623" y="231" width="672" height="678" key="search.everywhere.popup" timestamp="1602608996147">
<screen x="0" y="0" width="1920" height="1054" /> <screen x="0" y="0" width="1920" height="1054" />
</state> </state>
<state x="623" y="231" width="672" height="678" key="search.everywhere.popup/0.0.1920.1054@0.0.1920.1054" timestamp="1602599024210" /> <state x="623" y="231" width="672" height="678" key="search.everywhere.popup/0.0.1920.1054@0.0.1920.1054" timestamp="1602608996147" />
</component> </component>
</project> </project>

View file

@ -5,34 +5,6 @@ using System.Text.RegularExpressions;
namespace AusPostCode { namespace AusPostCode {
public class Barcode { public class Barcode {
private readonly struct BarcodeFragment {
public EncodingFormat TypicalFormat { get; }
public int Length { get;}
public int Offset { get; }
public BarcodeFragment(EncodingFormat typicalFormat, int length, int offset) {
TypicalFormat = typicalFormat;
Length = length;
Offset = offset;
}
}
private readonly Dictionary<string, BarcodeFragment> _fragments = new Dictionary<string, BarcodeFragment> {
["FormatControlCode"] = new BarcodeFragment(EncodingFormat.N, 4, 2),
["SortingCode"] = new BarcodeFragment(EncodingFormat.N, 16, 6),
["CustomerInformation2"] = new BarcodeFragment(EncodingFormat.C, 16, 22),
["CustomerInformation3"] = new BarcodeFragment(EncodingFormat.C, 31, 22),
["ErrorCorrection"] = new BarcodeFragment(EncodingFormat.BarToDecimal, 12, - 16),
};
private enum EncodingFormat {
N,
C,
BarToDecimal,
}
private int _formatCode;
private readonly Dictionary<int, string> _formatTable = new Dictionary<int, string> { private readonly Dictionary<int, string> _formatTable = new Dictionary<int, string> {
[0] = "Null Customer Barcode", [0] = "Null Customer Barcode",
[11] = "Standard Customer Barcode", [11] = "Standard Customer Barcode",
@ -44,6 +16,20 @@ namespace AusPostCode {
[77] = "International Business Reply Paid", [77] = "International Business Reply Paid",
}; };
private readonly Dictionary<string, BarcodeFragment> _fragments = new Dictionary<string, BarcodeFragment> {
["FormatControlCode"] = new BarcodeFragment(EncodingFormat.N, 4, 2),
["SortingCode"] = new BarcodeFragment(EncodingFormat.N, 16, 6),
["CustomerInformation2"] = new BarcodeFragment(EncodingFormat.C, 16, 22),
["CustomerInformation3"] = new BarcodeFragment(EncodingFormat.C, 30, 22),
["ErrorCorrection"] = new BarcodeFragment(EncodingFormat.BarToDecimal, 12, -16),
};
// TODO: make these consts
private readonly char[] _lower = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
private readonly char[] _upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
private readonly int _formatCode;
public Barcode(string code) { public Barcode(string code) {
Code = code; Code = code;
// - check for start and end bars // - check for start and end bars
@ -68,20 +54,23 @@ namespace AusPostCode {
// process Customer Information, if necessary // process Customer Information, if necessary
// TODO: actually do this, and get a code to test it on. also, ensure that customer codes are the right length // TODO: actually do this, and get a code to test it on. also, ensure that customer codes are the right length
if (_formatCode == 59) { if (_formatCode == 59) {
Console.WriteLine("This code has a Customer Information field, but I don't know how to process that yet 0uo"); Console.WriteLine("This code has a Customer Information 2 field, but I don't know how to process that yet 0uo");
} else if (_formatCode == 62) { }
Console.WriteLine("This code has a Customer Information field, but I don't know how to process that yet 0uo"); else if (_formatCode == 62) {
Console.WriteLine($"Customer info: [{GetFragment(_fragments["CustomerInformation3"])}]");
} }
// process Reed-Solomon Error Correction Bars // process Reed-Solomon Error Correction Bars
// TODO: actually validate the barcode // TODO: actually validate the barcode
Console.WriteLine(BaseConversion.FromBase(GetFragment(_fragments["ErrorCorrection"]), 64)); Console.WriteLine(BaseConversion.FromBase(GetFragment(_fragments["ErrorCorrection"]), 64));
} }
public int SortingCode { get; set; } public int SortingCode { get; set; }
public int CustomerInformation { get; set; } public int CustomerInformation { get; set; }
public string Format => _formatTable.ContainsKey(_formatCode) ? _formatTable[_formatCode] : $"Unknown ({_formatCode})";
public string Format =>
_formatTable.ContainsKey(_formatCode) ? _formatTable[_formatCode] : $"Unknown ({_formatCode})";
private List<string> Warnings { get; } = new List<string>(); private List<string> Warnings { get; } = new List<string>();
private string Code { get; } private string Code { get; }
@ -113,14 +102,79 @@ namespace AusPostCode {
} }
else if (chunk.Contains("3")) { else if (chunk.Contains("3")) {
// not a ternary number // not a ternary number
throw new ArgumentException($"{chunk} is not a valid identifier for format {data.ToString()}."); throw new ArgumentException($"{chunk} is not a valid identifier for format {data}.");
} }
else { else {
sb.Append(BaseConversion.FromBase(chunk, 3)); sb.Append(BaseConversion.FromBase(chunk, 3));
} }
break; break;
case EncodingFormat.C: case EncodingFormat.C:
// table C is a bit of a doozy.
// firstly, check for 222, which is zero.
if (chunk == "222") {
sb.Append("0");
}
// if it's any other valid ternary number (only digits 0,1,2), it's a capital letter.
else if (!chunk.Contains("3")) {
sb.Append(_upper[BaseConversion.FromBase(chunk, 3)]);
}
// if it starts with a 3, but is otherwise a valid ternary number, it's a digit from 1 through 9.
// the sequence is 300, 301, 302, 310, 311...
// because it starts at 0 (after stripping the leading 3), we add 1.
else if (chunk.StartsWith("3") && !chunk.Substring(1).Contains("3")) {
sb.Append(BaseConversion.FromBase(chunk.Substring(1), 3) + 1);
}
// 003 is space.
else if (chunk == "003") {
sb.Append(" ");
}
// 013 is hash.
else if (chunk == "013") {
sb.Append("#");
}
// and finally, anything that doesn't fall into any of the above is a lowercase letter.
else {
// this is by far the most difficult part when it comes to parsing the barcode formats (so far).
// i'm really bad at maths, and it took me a while to get this function into something (semi) readable
// down from the multi-cell spreadsheet formula mess that it started out as.
// i think this is the first time in my life i've ever done maths in a base other than 10, unless you
// count converting time differences.
// starting from 023, the lowercase numbers are expressed by a cyclical pattern.
// each "cycle" lasts for seven letters. let's use the letters "bcdefgh" as an example.
// b is 030 (12 in decimal). c follows at 031, d at 032, and e at 033. this is the first half of the cycle.
// during the second half of the cycle, letters are spaced *four* numbers apart,
// instead of one number apart like before.
// this means that e (033q == 15d) is *not* followed by f at 100q (16d), but at 103q (19d).
// g is found at 113q (23d), and then h is found at 123q (27d).
// i follows at 130q (28d), and the cycle repeats.
// the cycle resets at multiples of 16, which is very useful.
// the letters start at 11d, so we subtract 11 to start from zero instead.
var x = BaseConversion.FromBase(chunk, 4) - 11;
// you can tell how many times the cycle has looped by counting how many times 16 divides into the chunk.
// because the cycle is seven steps long, we should add 7 for every time 16 goes into the chunk.
// additionally, if we add 10 to x (and therefore making it effectively (chunk - 1)),
// we can mod it with 16 to get the repeating sequence '10, 11, 12, 13, 14, 2, 6'.
// we can use max() to replace the 2 with a 5, giving us '10, 11, 12, 13, 14, 5, 6'.
// if we only keep the units digit (by doing modulo 10), we get '0, 1, 2, 3, 4, 5, 6'.
// now we have a way to tell how many times we've completed the cycle (how many 16s go into the chunk),
// and a way to tell what step we're on in the cycle, we can combine these two pieces of knowledge to
// turn the messy letter codes into a set of integers from 0 to 25, increasing linearly by 1.
// in other words, when we're given a chunk like "032", we can tell that it refers to the 4th letter of
// the alphabet, and return that.
// i know the way this function is written is slightly unwieldy, but at the very least, it's better than
// wolfram alpha's suggested alternative form:
// -10 floor(1/10 max(5, x - 16 floor((x + 10)/16) + 10)) + max(5, -16 floor((x + 10)/16) + x + 10) + 7 floor(x/16)
// i guess wolfram really doesn't like the mod function? 0uo
sb.Append(_lower[x / 16 * 7 + Math.Max((x + 10) % 16, 5) % 10]);
}
break; break;
case EncodingFormat.BarToDecimal: case EncodingFormat.BarToDecimal:
@ -167,6 +221,7 @@ namespace AusPostCode {
else { else {
sb.Append(BaseConversion.FromBase(chunk, 3)); sb.Append(BaseConversion.FromBase(chunk, 3));
} }
break; break;
case EncodingFormat.C: case EncodingFormat.C:
@ -182,5 +237,23 @@ namespace AusPostCode {
return sb.ToString(); return sb.ToString();
} }
private readonly struct BarcodeFragment {
public EncodingFormat TypicalFormat { get; }
public int Length { get; }
public int Offset { get; }
public BarcodeFragment(EncodingFormat typicalFormat, int length, int offset) {
TypicalFormat = typicalFormat;
Length = length;
Offset = offset;
}
}
private enum EncodingFormat {
N,
C,
BarToDecimal,
}
} }
} }

View file

@ -29,9 +29,12 @@ namespace AusPostCode {
// - a filler bar of 3 // - a filler bar of 3
// - a reed-solomon code of 001101103221 == 10826817 // - a reed-solomon code of 001101103221 == 10826817
// - end bars // - end bars
const string testCode = "1301012112011202120020300110110322113"; // const string testCode = "1301012112011202120020300110110322113";
var barcode = new Barcode(testCode); // const string testCodeCustomer3 = "1320021211120120021201000001002300301302333333333333313133002021313";
const string testCodeCustomer3 = "1320021211120120021201003021130003120033203230023003313133002021313";
var barcode = new Barcode(testCodeCustomer3);
} }
public class Options { public class Options {