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

EAN13 Barcode Encoding in Haskell: How to test it?

我正在完成 chapter 12 of Real World Haskell. In this chapter, the author explains how to perform Barcode Recognition with 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"

为了确保我对函数的测试是正确的?

非常感谢您

您的 1 和 0 序列似乎存在三个问题。第一个是您的 [A] EAN-13 中心代码似乎覆盖了您的第六个字符的开头。它确实应该在 [B] 所在的位置。并且您在序列的末尾附加了额外的 4 个零和一个额外的结束标记。

这是一个可以生成校验和并布置 1 和 0 的工具:

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();
}
<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>

如果你想看实际生成的条码,我这里有codepen。它不添加格式化文本,但条形码扫描。

您的实现中有两个错误:

首先,在 encodeDigits 中,您在应该 splitAt 6 的时候写了 splitAt 5。这修复了@Brian Anderson 指出的编码错误。

其次,在 bestScores 中,您写了:

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

你应该写的时候:

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

这修复了您的解码错误。

我希望我可以说我用我超人的调试技巧找到了这些错误,但我恰好有自己的 Barcode.hs 副本,那是几年前我自己完成第 12 章的时候。