我继承了银行界面解析器。以前的开发人员实际上做得很漂亮。从银行进来的文件是固定长度字段。他从下载中解析该记录的方式是
public static final String HEADER_RECORD_REGEX = "^(\\d{3})(\\d{12})(.{20})(\\d\\d)(\\d\\d)(\\d\\d)(\\d{12})(\\d\\d)$";
private static final int BANK_ID = 1;
private static final int ACCOUNT_ID = 2;
private static final int COMPANY_NAME = 3;
private static final int MONTH = 4;
private static final int DAY = 5;
private static final int YEAR = 6;
private static final int SEQUENCE = 7;
private static final int TYPE_CODE = 8;
private static final int GROUP_COUNT = TYPE_CODE;
if ( GROUP_COUNT == matcher.groupCount() ) {
setBankId( matcher.group( BANK_ID ) );
setAccountId( matcher.group( ACCOUNT_ID ) );
setCompanyName( matcher.group( COMPANY_NAME ) );
setProcessDate( matcher.group( MONTH ), matcher.group( DAY ),
matcher.group( YEAR ) );
setSeqNumber( matcher.group( SEQUENCE ) );
setTypeCode( matcher.group( TYPE_CODE ) );
}
我有一个新的要求来反转这个过程并实际从银行生成模拟文件,以便我们可以测试。使用这种方法,有没有办法可以使用相同的正则表达式方法生成文件来反转流程,或者我只是回到构建标准解析器。
感谢
答案 0 :(得分:1)
这基本上可以满足您的要求。你可以玩它直到它符合你的需要。
import java.util.*;
class Main
{
public static String getLine(String bankID, String acctID, String companyName, String month, String day, String year, String seq, String typeCode)
{
return new Formatter()
.format("%3.3s%12.12s%20.20s%2.2s%2.2s%2.2s%12.12s%2.2s",
bankID, acctID, companyName, month,
day, year, seq, typeCode)
.toString(); // 1 semicolon, technically a 1 liner. aww yeah
}
public static void main(String[] args)
{
String tester = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
System.out.println(getLine(tester, tester, tester, tester,
tester, tester, tester, tester));
}
}
该示例的输出是:
123123456789ABC123456789ABCDEFGHIJK121212123456789ABC12
答案 1 :(得分:0)
如果通过反转意味着将对象输出到文件,则解析器不是您需要的。您需要做的就是实现一个方法,该方法使用与文件类似的格式输出相同的数据成员。您可以将String.format与正则表达式中的字段长度一起使用。通过一些重构,您可以提取正则表达式和字符串格式之间的共性,尽管您可能认为这是一种过度杀伤,因为这个正则表达式非常简单。
答案 2 :(得分:0)
你需要放弃让正则表达式控制你。如果你以另一种方式定义你的结构(我使用下面的enum
),你可以从中导出你的正则表达式和格式化程序,那么代码不仅会变得更具可扩展性,而且你也可以制作一个编组器和也是一个unmarshaller。
这样的事情可能是一个好的开始:
public class BankRecords {
static enum AccountField {
BANK_ID("\\d", 3) {
@Override
void fill ( Account a, String s ) {
a.bankId = s;
}
},
ACCOUNT_ID("\\d", 12) {
@Override
void fill ( Account a, String s ) {
a.accountID = s;
}
},
COMPANY_NAME(".", 20) {
@Override
void fill ( Account a, String s ) {
a.companyName = s;
}
},
MONTH("\\d", 2) {
@Override
void fill ( Account a, String s ) {
a.month = s;
}
},
DAY("\\d", 2) {
@Override
void fill ( Account a, String s ) {
a.day = s;
}
},
YEAR("\\d", 2) {
@Override
void fill ( Account a, String s ) {
a.year = s;
}
},
SEQUENCE("\\d", 12) {
@Override
void fill ( Account a, String s ) {
a.seqNumber = s;
}
},
TYPE_CODE("\\d", 2) {
@Override
void fill ( Account a, String s ) {
a.typeCode = s;
}
};
// The type string in the regex.
final String type;
// How many characters.
final int count;
AccountField(String type, int count) {
this.type = type;
this.count = count;
}
// Each field can fill its part in the Account.
abstract void fill ( Account a, String s );
// My pattern.
static Pattern pattern = Pattern.compile(asRegex());
public static Account parse ( String record ) {
Account account = new Account ();
// Fire off the matcher with the regex and put each field in the Account object.
Matcher matcher = pattern.matcher(record);
for ( AccountField f : AccountField.values() ) {
f.fill(account, matcher.group(f.ordinal() + 1));
}
return account;
}
public static String format ( Account account ) {
StringBuilder s = new StringBuilder ();
// Roll each field of the account into the string using the correct length from the enum.
return s.toString();
}
private static String regex = null;
static String asRegex() {
// Only do this once.
if (regex == null) {
// Grow my regex from the field definitions.
StringBuilder r = new StringBuilder("^");
for (AccountField f : AccountField.values()) {
r.append("(").append(f.type);
// Special case count = 1 or 2.
switch (f.count) {
case 1:
break;
case 2:
// Just one more.
r.append(f.type);
break;
default:
// More than that shoudl use the {} notation.
r.append("{").append(f.count).append("}");
break;
}
r.append(")");
}
// End of record.
r.append("$");
regex = r.toString();
}
return regex;
}
}
public static class Account {
String bankId;
String accountID;
String companyName;
String month;
String day;
String year;
String seqNumber;
String typeCode;
}
}
注意每个enum
如何封装每个字段的本质。类型,字符数以及它在Account
对象中的位置。