Haskell中的EAN13条形码编码:如何测试?

时间:2017-10-19 08:39:26

标签: haskell testing encoding barcode decoding

我正在完成chapter 12 of Real World Haskell。在本章中,作者解释了如何使用EAN13 encoding执行条形码识别。

我从the book snippets into my repo复制了大部分代码,当我最终到达以检查我的300多行代码是否按预期工作时,我得到了一个坏消息:

-- Finding the Correct Sequence
*Main> let input = zip (runLengths $ encodeEAN13 "9780132114677") (cycle [Zero, One])
*Main> listToMaybe . solve . candidateDigits $ input
Just [0,2,0,1,0,0,0,0,0,0,0,0,1] -- WRONG Actual
Just [9,7,8,0,1,3,2,1,1,4,6,7,7] -- Expected

自从这本书出版以来,我注意到一些类型的签名已经改变,例如:

$ ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Prelude> import qualified Data.Map as M
Prelude M> :t M.lookup
M.lookup :: Ord k => k -> M.Map k a -> Maybe a
-- in the book: M.lookup :: (Ord k, Monad m) => k -> M.Map k a -> m a

我尝试在GHCi中重现每一个例子,除了最后一个例外,我总是得到与本书相同的结果。

是否有人在本书中介绍了该主题?

作者并未解释每一行代码,尤其是input变量未定义let input = zip (runLengths $ encodeEAN13 "9780132114677") (cycle [Zero, One])

一些用于测试的EAN13编码条码?

如果没有人知道这本书,你会有一些 EAN13编码的条形码样本,例如:

*Main M> encodeEAN13 "9780132114677"
"101011101100010010100111001100101000010101011011001100110110011010111001010000100010010001001010000101"

确保我对功能的测试是正确的吗?

非常感谢您提前

2 个答案:

答案 0 :(得分:2)

您的实施中有两个错误:

首先,在encodeDigits中,您应该splitAt 5splitAt 6。这修复了@Brian Anderson注意到的编码错误。

其次,在bestScores中,您已写过:

[(distance d (scaleToOne ps), n) | d <- srl, n <- digits]

你应该写的时候:

zip [distance d (scaleToOne ps) | d <- srl] digits

这可以解决您的解码错误。

我希望我可以说我使用我的超人调试技巧来找到这些错误,但我刚刚在几年前自己做了第12章时,碰巧拥有自己的Barcode.hs副本。

答案 1 :(得分:1)

enter image description here

您的1和0序列看起来有三个问题。第一个是你的[A] EAN-13中心代码似乎覆盖了你的第六个角色的开头。应该真的是[B]的位置。而且你已经有了额外的4个零,并且在你的序列结束时添加了一个额外的结束标记。

这是一个工具,用于生成校验和并布置1和0:

&#13;
&#13;
var arrayCodeEANBin, arrayStructEAN;
arrayCodeEANBin = [ [ '0001101', '0011001', '0010011', '0111101', '0100011', '0110001', '0101111', '0111011', '0110111', '0001011' ], [ '0100111', '0110011', '0011011', '0100001', '0011101', '0111001', '0000101', '0010001', '0001001', '0010111' ], [ '1110010', '1100110', '1101100', '1000010', '1011100', '1001110', '1010000', '1000100', '1001000', '1110100' ] ];
arrayStructEAN = ['000000', '001011', '001101', '001110', '010011', '011001', '011100', '010101', '010110', '011010']

var strRaw = "";
var strText = "";

function funcEAN() { // EAN-13
var intSumOdd = 0, intSumEven = 0, intCheck, i, j, strStruct;
// Compute check digit and add it to raw string
 for (i = 0; i < 12; i += 2) {
  intSumEven += parseInt(strText[i]);
  intSumOdd += parseInt(strText[i+1]);
 }
 intCheck = ((intSumOdd * 3) + intSumEven) % 10;
 if (intCheck > 0) {
 	intCheck = 10 - intCheck;
 }
 strText += intCheck;
// Converts Code EAN array into string of 1's and 0's
 strRaw = "101"
// First six bar sequences
 for (i = 1; i < 7; i += 1) {
   strStruct = arrayStructEAN[strText[0]];
   strRaw += arrayCodeEANBin[strStruct[i-1]][strText[i]];
 }
// Middle sequence
 strRaw += "01010";
// Last six bar sequences, including check digit
 for (i = 0; i < 6; i += 1) {
  strRaw += arrayCodeEANBin[2][strText[i+7]];
 }
 strRaw += "101";
} // End EAN-13


var buttonBarcode = document.getElementById("btnGenBar");
buttonBarcode.onclick = function () {
 strText = document.getElementById("textBarcode").value;
 funcEAN();
 document.getElementById("textRaw").value = strRaw;
 document.getElementById("textRaw").select();
}
&#13;
<head>
<title>EAN-13 Barcodes in vanilla JavaScript</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
</head>
<body>
 <div id="inputForm">
 	Enter Text:&nbsp;<input type="text" id="textBarcode" tabindex=1/>
 	&nbsp;<input type="button" id="btnGenBar" value="Gen 1's and 0's" tabindex=4/>
 </div>
 <p></p>
 <div id="result"></div>
 <p></p>
 <textarea rows="3" cols="110" id="textRaw" tabindex=0></textarea>
<script type="text/javascript" src="./SO_JS-EAN-13.js"></script>
</body>
</html>
&#13;
&#13;
&#13;

如果您想查看生成的实际条形码,我有一个codepen。它不会添加格式化文本,但条形码会扫描。