从PDF中提取表格

时间:2014-07-14 20:26:58

标签: c# pdf itext text-extraction

我需要在C#中使用iText的帮助。我正在尝试从PDF文件中提取表并将其保存到新的CSV文件中,将值保存在正确的位置。为此,我认为解决方案是创建一个二维数组来组织数据。

使用iText从PDF中提取所有信息,我看到有可能获得一些数字数据,这些数据似乎是页面上一段文本的位置,我根据这些索引组织了我的数组。它不起作用,文本完全分散在各种不同的细胞中。现在,我想知道这些值的含义,因为它们不遵循“正确”的顺序,我想知道是否可以用这个来组织未来的表。

我正在使用“;”作为分隔符单元格。

为了测试,我正在使用此PDF http://www.americana.sp.gov.br/americanaV5/download/contasPublicas/Despesa_Categoria_Economica_2014.pdf

这是我的代码:

protected void Button2_Click(object sender, EventArgs e)
{
    try
    {
        TextBox2.Text = "";
        byte[] conteudo = download(TextBox1.Text);

        if (conteudo != null)
        {

            PdfReader leitorp = new PdfReader(conteudo);
            ITextExtractionStrategy estrategia = new SimpleTextExtractionStrategy();

            List<Celula> celulas = new List<Celula>();

            int i, j;

            for (i = 1; i <= leitorp.NumberOfPages; i++)
            {
                //Total and crude extraction of all information from text in PDF via iText, separate lines in an array of strings.
                string[] linhas = (Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, leitorp.GetPageContent(i)))).Split('\n');

                for (j = 1; j < linhas.Length; j++)
                {
                    if (linhas[j].Length > 2)
                    {
                        if (linhas[j].Substring(0, 2).Equals("BT"))
                        {
                            string[] campos = linhas[j].Split(' ');
                            Celula umacelula = new Celula();
                            umacelula.coluna = float.Parse(campos[1]);
                            umacelula.linha = float.Parse(campos[2]);

                            linhadodebug = j;
                            int t1 = linhas[j].IndexOf('(');
                            int t2 = linhas[j].LastIndexOf(')');

                            umacelula.conteudo = System.Text.RegularExpressions.Regex.Replace((linhas[j].Substring(linhas[j].IndexOf('(') + 1, (linhas[j].LastIndexOf(')') - 1 - linhas[j].IndexOf('(')))), @"\s\s+", "");

                            celulas.Add(umacelula);
                        }
                    }
                }
            }

            leitorp.Close();

            string[] totallinhas = new string[celulas.Count];
            string[] totalcolunas = new string[celulas.Count];

            for (i = 0; i < celulas.Count; i++)
            {
                totallinhas[i] = celulas[i].linha.ToString();
                totalcolunas[i] = celulas[i].coluna.ToString();
            }

            totallinhas = totallinhas.Distinct().ToArray();
            totalcolunas = totalcolunas.Distinct().ToArray();

            Array.Sort(totallinhas);
            Array.Reverse(totallinhas);

            Array.Sort(totalcolunas);
            Array.Reverse(totalcolunas);

            string[,] matriz = new string[totallinhas.Length + 1, totalcolunas.Length + 1];

            for (i = 1; i < totallinhas.Length; i++)
            {
                matriz[i, 0] = totallinhas[i - 1].ToString();
            }

            for (i = 1; i < totalcolunas.Length; i++)
            {
                matriz[0, i] = totalcolunas[i - 1].ToString();
            }

            int z;
            for (i = 0; i < celulas.Count(); i++)
            {
                for (j = 1; j < matriz.GetLength(0); j++)
                {
                    for (z = 1; z < matriz.GetLength(1); z++)
                    {
                        if ((celulas[i].linha.ToString().Equals(matriz[j, 0])) && (celulas[i].coluna.ToString().Equals(matriz[0, z])))
                        {
                            matriz[j, z] = celulas[i].conteudo.ToString();
                        }
                    }
                }
            }

            StringWriter texto = new StringWriter();

            for (i = 0; i < matriz.GetLength(0); i++)
            {
                for (j = 0; j < matriz.GetLength(1); j++)
                {
                    texto.Write(matriz[i, j] + ";");
                }
                texto.WriteLine();
            }

            Response.ContentType = "text/plain";
            Response.AddHeader("content-disposition", "attachment;filename=" + string.Format("teste-{0}.csv", string.Format("{0:ddMMyyyy}", DateTime.Today)));
            Response.Clear();

            using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.UTF8))
            {
                writer.Write(texto.ToString());
            }
            Response.End();

        }

    }
    catch (Exception E)
    {
        TextBox2.Text = "Erro Button2_Click: " + E.Message + " # " + linhadodebug.ToString();
    }

}

在这里,celula(cell)的结构和下载文件的方法:

public struct Celula
{
    public float coluna;
    public float linha;
    public string conteudo;

    public Celula(float coluna, float linha, string conteudo)
    {
        this.coluna = coluna;
        this.linha = linha;
        this.conteudo = conteudo;
    }

    public Celula(Celula celula)
    {
        this.coluna = celula.coluna;
        this.linha = celula.linha;
        this.conteudo = celula.conteudo;
    }
}

protected byte[] download(string url)
{
    try
    {
        WebRequest endereco = HttpWebRequest.Create(url);

        Stream leitor = endereco.GetResponse().GetResponseStream();

        MemoryStream memoria = new MemoryStream();

        byte[] conteudo = null;

        int count = 0;

        do
        {
            byte[] buffer = new byte[1024];
            count = leitor.Read(buffer, 0, 1024);
            memoria.Write(buffer, 0, count);
        }
        while (leitor.CanRead && count > 0);

        // Converte da memória direto para bytes
        conteudo = memoria.ToArray();

        if (conteudo != null)
        {
            return conteudo;
        }
        else
        {
            TextBox2.Text = "Error: download null.";
            return null;
        }

    }
    catch (Exception E)
    {
        TextBox2.Text = "Error download: " + E.Message;
        return null;
    }

}

这是一个非盈利项目。我希望你能帮助我。谢谢!

0 个答案:

没有答案