在Java 8流中使用正则表达式和迭代索引

时间:2017-01-16 23:03:36

标签: regex java-8 java-stream

我正在尝试从银行对帐单中提取交易并将其放入数据库中。

作为第一步,我在statement.txt文件中有我的声明,它包含以下示例数据。

...some lines of text

11/29/16 Online scheduled transfer to SAV 8075 Confirmation# 1098489998 -500.00
11/29/16 KEEP THE CHANGE TRANSFER TO ACCT 8075 FOR 11/29/16 -0.09
11/30/16 CHECKCARD 1129 TONNELLE MART PROFESSIO NORTH BERGEN NJ
24055236335400648000752
-17.76
11/30/16 CHECKCARD 1129 STATE FARM 800-956-6310 IL 24610436334004074264281 RECURRING -297.09

...some more transactions and text.

如您所见,一些数据正在流入下一行。 我正在将这些行读成流,如下所示。

Stream<String> lines = Files.lines(Paths.get("statement.txt"),Charset.defaultCharset());

现在,无论是否有Streams,我如何实现以下目标?

  1. 任何以mm / dd / yy格式开头并以金额格式结尾的行都应添加到另一个名为“transactions”的文本文件或arrayList中
  2. 当一行换成多行时(假设一个事务分成最多3行并且我们知道它),这些行应该连接并返回。
  3. 以下是我的日期和金额的正则表达式:

    String date= "^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}\\s.";
    String amount = "^-?\\d+(\\.\\[0-9][0-9]).";
    

2 个答案:

答案 0 :(得分:2)

你问了很多东西。我建议你把它们分解一下,这将有助于你看到你所要求的并不是太难:文件读取,解析,连接,然后文件写入。拆分一切。

我尝试过使用Streams,并尝试使用带有谓词的每个方法。

我对文件写作或返回的意思不太清楚:

  
      
  1. 任何应该添加到另一个文本文件或arrayList中的行,称为“transactions
  2. ”   
  3. 当一行分成多个[...]时,这些行应该连接并返回。
  4.   

我已将分割线连接到一行,然后您可以根据需要执行任何操作。

这是我的(完全未经测试,但正在编译)代码:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestStream {
    public void main(String[] argc) throws IOException{
        Stream<String> lineStream = streamFile("testFile.txt");  // Stream Input text
        List<String> transactionList = new ArrayList<>(); // Prepare result list
        Map<Boolean, List<String>> transactionstream = lineStream.collect(Collectors.partitioningBy(s -> s.matches("^[0-3]?[0-9]/[0-3]?[0-9]/(?:[0-9]{2})?[0-9]{2}\\s")));
        transactionstream.forEach((success, transactionContent) -> {
            if(!success)
                return;
            String concat = transactionContent.stream().collect(Collectors.joining());
            transactionList.add(concat);
        });
    }

    public Stream<String> streamFile(final String filename) throws IOException {
        Stream<String> stream = Files.lines(Paths.get(filename));
        return stream;
    }
}

基本上我:

  • 使用Files.lines()
  • 将文件转储到Stream
  • 当行以日期开始时,将行分割为分割 - &GT;这给出了一个Map<Boolean, List<String>>,其中boolean表示匹配,List包含连续的行,其中只有第一行以日期开头(即它的事务)
  • 在地图上使用forEach,然后流式传输分段事务并使用连接的收集器,最后将连接的字符串放在transactionList中。
  • 完成工作,结果在transactionList中。我留给你做一些有用的交易清单。

我认为不可能充分发挥Stream s的潜力来完成这项任务,因为:

  • 在放入Streams
  • 之前,必须先阅读整个文件
  • 某些行是相互依赖的,因此分区必须立即扫描整个文件

所以Streams将不会是懒惰的&amp;高效。但它比手动解决方案短得多。

警告:我没有添加任何分隔符来连接这些行,这可能会弄乱内容。您可能需要一个分隔符。幸运的是,您可以使用其他 Collector.joining()方法做到这一点!

答案 1 :(得分:1)

我在下面解决了它...它不完美..帮助我提高

将此方法放在任何具有psvm

的类中
static ArrayList<String> printMatchers(){
        String fileName = "/Users/dhananjayraparla/Desktop/GitHub/Groovy/BankStatementViewer/src/main/resources/Statements.txt";
        Pattern date = Pattern.compile("^[0-9][0-9]/[0-9][0-9]/[0-9][0-9]");
        Pattern amount = Pattern.compile("-?\\d{0,3},?\\d{0,3}\\.\\d{2}$");
        //read file into stream, try-with-resources
        String previous=new String();
        List<String> lines = null;
        try {
            lines = Files.readAllLines(Paths.get(fileName));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        ArrayList<String> filteredList = new ArrayList<>();
        for (int i = 0; i < lines.size(); i++) {

            Matcher dt = date.matcher(lines.get(i));
            Matcher amt = amount.matcher(lines.get(i));

            if ( dt.find() && amt.find() ){
                    System.out.println( lines.get(i) );
                    filteredList.add( lines.get(i) );
            } 
            else if (i<lines.size()-2) {
                String temp1 = lines.get(i)+" "+lines.get(i+1);
                Matcher dt2 = date.matcher(temp1);
                Matcher amt2 = amount.matcher(temp1);

                String temp2 = lines.get(i)+" "+lines.get(i+1)+" "+lines.get(i+2);
                Matcher dt3 = date.matcher(temp2);
                Matcher amt3 = amount.matcher(temp2);
                if (dt2.find() && amt2.find()) {
                    System.out.println(temp1);
                    filteredList.add(temp1);
                } else if (dt3.find() && amt3.find()) {
                    System.out.println(temp2);
                    filteredList.add(temp2);
                } 
            }
        }
        try {
            Path out = Paths.get("/Users/dhananjayraparla/Desktop/GitHub/Groovy/BankStatementViewer/src/main/resources/filteredTransactionList.txt");
            Files.write(out,filteredList,Charset.defaultCharset());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filteredList;

    }

正如你所看到的......我写了自己的模式

Pattern date = Pattern.compile("^[0-9][0-9]/[0-9][0-9]/[0-9][0-9]");
Pattern amount = Pattern.compile("-?\\d{0,3},?\\d{0,3}\\.\\d{2}$");

并没有使用Java 8流。

这是我的输入

11/17/16 GAS MART AT BR  11/17 #000157975 PURCHASE GAS MART AT BRO     -1.75
continued on the next page
   !   = 1725 0868   !   October 20, 2016 to November 17, 2016
Page 6 of 6
Withdrawals and other subtractions - continued
Date Description Amount
11/17/16 PLANET FIT       DES:CLUB FEES  ID:1632102280753  INDN:       CO
ID:1710602737 PPD  PMT INFO:516-861-2109
-10.00
11/17/16 KEEP THE CHANGE TRANSFER TO  FOR 11/17/16 -0.99
Total withdrawals and other subtractions -$4,186.00
Service fees
Date Transaction description Amount
10/20/16 P199657         10/19 #000008705 WITHDRWL 199    FEE
-2.50

这是我的输出

11/17/16 GAS MART AT BR  11/17 #000157975 PURCHASE GAS MART AT BRO        NY -1.75
11/17/16 PLANET FIT       DES:CLUB FEES  ID:1632102280753  INDN:       CO ID:1710602737 PPD  PMT INFO:516-861-2109 -10.00
11/17/16 KEEP THE CHANGE TRANSFER TO  FOR 11/17/16 -0.99
10/20/16 P199657         10/19 #000008705 WITHDRWL 199   FEE -2.50

我想知道如何使用流来获得此结果