📄 bankcodescan.java
字号:
package com.xnulw.pro7;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* @author slmcygh
* 吐血,中午11点多开始思考这个题目,到现在已经是晚上11:50了,头晕脑胀的
* 现在代码已经是很乱了,其实思路并不复杂,实现起来也不困难,可就是有些细节问题你很难发现,要经过大量的
* 调试,然后再慢慢的修改。我现在怀疑还有胆量再做
*
* 欢迎大家转载,但请保留以上文字
* 同时欢迎大家访问我的博客 http://xnulw.blogcn.com
*
*/
//条形码元数据,即其中的某一位
class CodeData{
char[][] ch=new char[3][3];//记录某一个数值的七段表示
int dataValue; //相应的数值
public CodeData(){
dataValue=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
ch[i][j]='.';
}
public CodeData(int value,String firstline,String secondline,String thirdline){
dataValue=value;
ch[0]=firstline.toCharArray();
ch[1]=secondline.toCharArray();
ch[2]=thirdline.toCharArray();
}
}
public class BankCodeScan {
private CodeData[] codeDictionary;//十种可能的元数据,可称做字典
CodeData[] dataTmps=new CodeData[9];
private CodeData[] theCode=new CodeData[9];//某一个条形码,是由9个元数据组成的
private int notEqualNum;//记录条形码中元数据不在字典中的个数,这里的值不会大于1,当大于1时即已经表明这个条形码是不可识别的
private int notEqualInTheCode;//记录不在字典中的元数据在条形码的位置,只有当notEqualNum=1时才有含义,主要目标是为了后面的近似匹配
private BufferedReader inStream;
public BankCodeScan(){
try {
inStream=new BufferedReader(new FileReader("input.txt"));
} catch (FileNotFoundException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}
//字典初始化
public void initDictionary(){
codeDictionary=new CodeData[10];
for(int i=0;i<10;i++){
codeDictionary[i]=new CodeData();
}
char[][] dat0={
{'.','_','.'},
{'|','.','|'},
{'|','_','|'}
};
char[][] dat1={
{'.','.','.'},
{'.','.','|'},
{'.','.','|'}
};
char[][] dat2={
{'.','_','.'},
{'.','_','|'},
{'|','_','.'}
};
char[][] dat3={
{'.','_','.'},
{'.','_','|'},
{'.','_','|'}
};
char[][] dat4={
{'.','.','.'},
{'|','_','|'},
{'.','.','|'}
};
char[][] dat5={
{'.','_','.'},
{'|','_','.'},
{'.','_','|'}
};
char[][] dat6={
{'.','_','.'},
{'|','_','.'},
{'|','_','|'}
};
char[][] dat7={
{'.','_','.'},
{'.','.','|'},
{'.','.','|'}
};
char[][] dat8={
{'.','_','.'},
{'|','_','|'},
{'|','_','|'}
};
char[][] dat9={
{'.','_','.'},
{'|','_','|'},
{'.','_','|'}
};
codeDictionary[0].ch=dat0;
codeDictionary[0].dataValue=0;
codeDictionary[1].ch=dat1;
codeDictionary[1].dataValue=1;
codeDictionary[2].ch=dat2;
codeDictionary[2].dataValue=2;
codeDictionary[3].ch=dat3;
codeDictionary[3].dataValue=3;
codeDictionary[4].ch=dat4;
codeDictionary[4].dataValue=4;
codeDictionary[5].ch=dat5;
codeDictionary[5].dataValue=5;
codeDictionary[6].ch=dat6;
codeDictionary[6].dataValue=6;
codeDictionary[7].ch=dat7;
codeDictionary[7].dataValue=7;
codeDictionary[8].ch=dat8;
codeDictionary[8].dataValue=8;
codeDictionary[9].ch=dat9;
codeDictionary[9].dataValue=9;
}
//这个方法主要是用于判断当前元数据是否在字典中
public void equalJudge(CodeData[] theData,int theMetadataPosition){
int ntoEqualNumTag=0;//用于标识现在的元数据与字典中元数据都不相等的个数,如果等于10,则说明当前元数据不能在字典中找到
for(int num=0;num<10;num++){
int tag=ntoEqualNumTag;//tag主要用于判定当前元数据与字典中第num个元素是否相等
for(int i=-1;i<=1;i++) {
if(tag==(ntoEqualNumTag-1))break;//如果有小部分不相等,则其它部分没必要比较,这个设计我觉得非常酷
for(int j=-1;j<=1;j++)
if(!((i==-1 && j==-1)||(i==-1 && j==1)))
if(theData[theMetadataPosition].ch[i+1][j+1]!=codeDictionary[num].ch[i+1][j+1]){
ntoEqualNumTag++;//不等标记加1,当值为10时,则说明字典中没有与之相等的元素
break;
}
}
//比较一个元素,每小部分均相等,则整体相等
//下面是为条型码中的第theMetadataPosition+1个数据赋值
if(tag==ntoEqualNumTag){
theData[theMetadataPosition].dataValue=codeDictionary[num].dataValue;
break;
}
}
if(ntoEqualNumTag==10){
notEqualNum++;//条形码不在字典中的元数据加1
notEqualInTheCode=theMetadataPosition;//记录最后一个不在字典中的无数据的位置
}
}
//这个方法是在确定了整个条形码中只有一个元数据不确定时调用的匹配方法
//这里说的匹配不指相等,而是条形码中的一个元数据指可以添加一些笔画变成与字典中元素相等
public String isLikeJudge(CodeData[] theData,int notEqualInTheCode){
int notLikeTag=0;
int likeTag=0;//记录可匹配的元数据个数
for(int num=0;num<10;num++){
int tag2=notLikeTag;//tag2主要用于判定当前元数据与字典中第num个元素是否可匹配
for(int i=-1;i<=1;i++){
if(tag2==(notLikeTag-1))break;//如果有小部分不匹配,则其它部分没必要比较,这个设计我觉得非常酷
for(int j=-1;j<=1;j++)
if(!((i==-1 && j==-1)||(i==-1 && j==1)))
if(theData[notEqualInTheCode].ch[i+1][j+1]!=codeDictionary[num].ch[i+1][j+1]){
if(theData[notEqualInTheCode].ch[i+1][j+1]!='.'){
notLikeTag++;//不匹配加1
break;
}
}
}
//相等,则说明当前条形码中的元数据是可以匹配的,但还不确定匹配后的结果是否满足较验条件
if(tag2==notLikeTag){
int temp=theData[notEqualInTheCode].dataValue;//保存数值,一旦匹配的结果不满足较验条件,便于恢复
theData[notEqualInTheCode].dataValue=codeDictionary[num].dataValue;//改变数据
if(validata())likeTag++;
else
theData[notEqualInTheCode].dataValue=temp;//恢复数据
}
}
if(likeTag==0)return "failur"; //不可匹配
if(likeTag==1)return display();//当前元数据只可匹配一个字典中的数据
if(likeTag>1)return"ambiguou";//当前元数据可匹配多个字典中的数据
return null;
}
//对识别出来的条形码,读取其值
private String display() {
String str="";
for(int i=0;i<9;i++){
str+=theCode[i].dataValue;
}
//这里很重要,主要是让条形码还原最初扫描进来的状态
//因为,后面有可能多次对同一个条形码进行操作,而这些操作要求条形码具有最初的状态
for(int i=0;i<9;i++){
this.theCode[i]=new CodeData(dataTmps[i].dataValue,new String(dataTmps[i].ch[0]),
new String(dataTmps[i].ch[1]),new String(dataTmps[i].ch[2]));
}
return str;
}
//条形码扫描结果进行验证
private boolean validata() {
int sum=0;
for(int i=1;i<10;i++){
int tmp=(10-i)*theCode[i-1].dataValue;
sum+=tmp;
}
if((sum%11)==0)return true;
return false;
}
//对某一条具体的条形码进行处理
public void processACode(){
for(int i=0;i<9;i++){
//题目说过,扫描只可能最多出错一个数据
if(notEqualNum>1){
System.out.println("failur");
break;
}
equalJudge(theCode, i);//检查条形码第(i+1)个数据是否在字典中
}
//这里就是当条形码所有的数据都在字典中,即可识别时
//这里比较复杂,因为可识别的数据同样是可以是某个数据因为扫描错误而得到,如7->1,8->0等
if(notEqualNum==0){
//1.这里不仅要考虑识别出的条形码是否满足较验条件,
//2.同时又要考虑这些可识别的条形码是否是别的条形码因为扫描错误而得到
//最后结果只可能是3种情况,(1)都不满足(2)有多个满足(3)只有一个满足
//结合1,2两种情况,可以很容易的构建整个综合结果的逻辑
String result="";//用于保存综合两种考虑的输出结果
String s1="";//用于保存考虑1的输出结果
if(this.validata()){
s1=display();
}else{
s1="failur";
}
int num=0;
String s2="failur";//用于保存考虑2的输出结果
for(int i=0;i<9;i++){
// 这里因为,每一次元数据替代后就改变了原先条形码,因此这里要保证的是每一次替代后,又还原为原先的条形码
// 而这个操作,我们在display()方法中做了
String s2temp=this.isLikeJudge(theCode, i);
if("ambiguou".equals(s2temp)){
s2="ambiguou";
break;
}
else{
if(!"failur".equals(s2temp)){
if(!s2.equals(s2temp)){
s2=s2temp;
num++;
if(num>1){
s2="ambiguou";
break;
}
}
}
}
}
if("ambiguou".equals(s2)){
result=s2;
}else{
if("failur".equals(s2)){
if("failur".equals(s1)){
result="failur";
}else{
result=s1;
}
}else{
if("failur".equals(s1)){
result=s2;
}else{
if(s2.equals(s1)){
result=s2;
}else{
result="ambiguou";
}
}
}
}
System.out.println(result);
}
//有一个数据不可识别,notEqualInTheCode指明了该数据在条形码中的位置是(notEqualInTheCode+1)
//匹配该数据
if(notEqualNum==1)System.out.println(isLikeJudge(theCode, notEqualInTheCode));
}
//驱动类,出于习惯把正常的操作步骤组织在这个方法里
public void driver() throws IOException{
String firstline;
String secondline;
String thirdline;
//循环读取条形码并进行处理
while((firstline=inStream.readLine())!=null){
if((secondline=inStream.readLine())!=null && (thirdline=inStream.readLine())!=null){
for(int i=0;i<9;i++){
theCode[i]=new CodeData(0,firstline.substring(i*3, (i+1)*3),
secondline.substring(i*3, (i+1)*3),
thirdline.substring(i*3, (i+1)*3));
}
//这里就是把条形码的最初状态作一个备份,以便需要的时候,还原其初始状态
for(int i=0;i<9;i++){
dataTmps[i]=new CodeData(theCode[i].dataValue,new String(theCode[i].ch[0]),
new String(theCode[i].ch[1]),new String(theCode[i].ch[2]));
}
}
processACode();//处理这一条条形码
this.notEqualNum=0;//恢复状态,为处理下一条条形码作准备
this.notEqualInTheCode=0;
}
}
public static void main(String[] args) throws IOException{
BankCodeScan bc=new BankCodeScan();
bc.initDictionary();
bc.driver();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -