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:
parent
d290dbadad
commit
a34702dc6c
3 changed files with 161 additions and 80 deletions
|
@ -22,7 +22,6 @@
|
|||
<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$/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" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
|
@ -45,6 +44,7 @@
|
|||
<option value="$PROJECT_DIR$/BarcodeVersion.cs" />
|
||||
<option value="$PROJECT_DIR$/.gitignore" />
|
||||
<option value="$PROJECT_DIR$/BaseConversion.cs" />
|
||||
<option value="$APPLICATION_CONFIG_DIR$/scratches/scratch.txt" />
|
||||
<option value="$PROJECT_DIR$/Program.cs" />
|
||||
<option value="$PROJECT_DIR$/Barcode.cs" />
|
||||
</list>
|
||||
|
@ -65,6 +65,7 @@
|
|||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="XThreadsFramesViewSplitterKey" value="0.7161862" />
|
||||
<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="vue.rearranger.settings.migration" value="true" />
|
||||
</component>
|
||||
|
@ -96,7 +97,7 @@
|
|||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1602593942454</updated>
|
||||
<workItem from="1602593947835" duration="13843000" />
|
||||
<workItem from="1602593947835" duration="17273000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="initial commit, as they say">
|
||||
<created>1602597326777</created>
|
||||
|
@ -148,86 +149,86 @@
|
|||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</state>
|
||||
<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" />
|
||||
</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.center" 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="1602610374477">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.left" 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="1602610374476">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.right" 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="1602610374478">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.1.bottom" timestamp="1602607646287">
|
||||
<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="1602610374479">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.center" 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="1602610374479">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.left" 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="1602610374478">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.right" 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="1602610374479">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.2.bottom" timestamp="1602607646288">
|
||||
<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="1602610374481">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.center" timestamp="1602607646287">
|
||||
<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="1602610374480">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.left" 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="1602610374480">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.right" 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="1602610374480">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.3.bottom" timestamp="1602607646288">
|
||||
<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="1602610374482">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.center" 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="1602610374482">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.left" 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="1602610374481">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.right" 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="1602610374482">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.4.bottom" timestamp="1602607646289">
|
||||
<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="1602610374484">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.center" timestamp="1602607646288">
|
||||
<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="1602610374483">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.left" 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="1602610374483">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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.right" timestamp="1602607646289">
|
||||
<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="1602610374484">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</state>
|
||||
|
@ -240,6 +241,10 @@
|
|||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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="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">
|
||||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</state>
|
||||
|
@ -248,9 +253,9 @@
|
|||
<screen x="0" y="0" width="1920" height="1054" />
|
||||
</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="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" />
|
||||
</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>
|
||||
</project>
|
141
Barcode.cs
141
Barcode.cs
|
@ -5,34 +5,6 @@ using System.Text.RegularExpressions;
|
|||
|
||||
namespace AusPostCode {
|
||||
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> {
|
||||
[0] = "Null Customer Barcode",
|
||||
[11] = "Standard Customer Barcode",
|
||||
|
@ -44,6 +16,20 @@ namespace AusPostCode {
|
|||
[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) {
|
||||
Code = code;
|
||||
// - check for start and end bars
|
||||
|
@ -68,20 +54,23 @@ namespace AusPostCode {
|
|||
// 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
|
||||
if (_formatCode == 59) {
|
||||
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("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($"Customer info: [{GetFragment(_fragments["CustomerInformation3"])}]");
|
||||
}
|
||||
|
||||
// process Reed-Solomon Error Correction Bars
|
||||
// TODO: actually validate the barcode
|
||||
Console.WriteLine(BaseConversion.FromBase(GetFragment(_fragments["ErrorCorrection"]), 64));
|
||||
|
||||
}
|
||||
|
||||
public int SortingCode { 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 string Code { get; }
|
||||
|
||||
|
@ -113,14 +102,79 @@ namespace AusPostCode {
|
|||
}
|
||||
else if (chunk.Contains("3")) {
|
||||
// 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 {
|
||||
sb.Append(BaseConversion.FromBase(chunk, 3));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
case EncodingFormat.BarToDecimal:
|
||||
|
@ -167,6 +221,7 @@ namespace AusPostCode {
|
|||
else {
|
||||
sb.Append(BaseConversion.FromBase(chunk, 3));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EncodingFormat.C:
|
||||
|
@ -182,5 +237,23 @@ namespace AusPostCode {
|
|||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,12 @@ namespace AusPostCode {
|
|||
// - a filler bar of 3
|
||||
// - a reed-solomon code of 001101103221 == 10826817
|
||||
// - 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 {
|
||||
|
|
Loading…
Reference in a new issue