有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java反转基于正则表达式的解析器

我继承了一个银行接口解析器。以前的开发人员实际上做得很巧妙。从银行输入的文件是一个固定长度的字段。他解析下载的记录的方式如下

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

我有一个新的需求,需要逆转这个过程,并从银行实际生成模拟文件,以便我们可以进行测试。使用这个方法,是否有一种方法可以使用这个相同的正则表达式方法来反转生成文件的过程,或者我只是返回到构建一个标准解析器

谢谢


共 (3) 个答案

  1. # 1 楼答案

    你需要避免让正则表达式控制你。如果您以另一种方式定义您的结构(我使用下面的enum),您可以从中派生正则表达式和格式化程序,那么不仅代码将变得更加可扩展,而且您还可以从中生成封送器和解封器

    这样的事情可能是一个好的开始:

    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对象中的位置

  2. # 2 楼答案

    这基本上满足了你的要求。你可以玩它,直到它满足你的需要

    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

    Here's the ideone.

  3. # 3 楼答案

    若反转的意思是将一个对象输出到一个文件中,那个么解析器并不是你们所需要的。您所需要做的就是实现一个方法,该方法使用类似的格式将相同的数据成员输出到文件中。你可以使用字符串。使用正则表达式中的字段长度格式化。通过一些重构,您可以在正则表达式和字符串格式之间提取共性,尽管您可能认为这是一种过度的操作,因为这个正则表达式相当简单。p>