Cara terprogram secara terprogram melalui subskrip, superskrip dan persamaan yang ditemukan dalam dokumen Word

12

Saya memiliki beberapa dokumen Word, masing-masing berisi beberapa ratus halaman data ilmiah yang meliputi:

  • Formula kimia (H2SO4 dengan semua subskrip & superskrip yang tepat)
  • Bilangan ilmiah (eksponen diformat menggunakan superskrip)
  • Banyak Persamaan Matematika. Ditulis menggunakan editor persamaan matematika di Word.

Masalahnya, menyimpan data ini di Word tidak efisien bagi kami. Jadi kami ingin menyimpan semua informasi ini dalam database (MySQL). Kami ingin mengonversi pemformatan ke LaTex.

Apakah ada cara untuk beralih melalui semua subkrip, superskrip dan persamaan dalam dokumen Word menggunakan VBA?

cakar
sumber
Sudahkah Anda berpikir tentang mengekstraksi data xml dari dalam dokumen itu sendiri? Semua Microsoft Documents 2007+ (.docx) pada dasarnya adalah file xml terkompresi. Anda bisa mengambilnya menggunakan parser xml.
James Mertz
itu terlalu panjang untuk dikirim sebagai komentar, jadi saya menambahkan sebagai jawaban.
James Mertz

Jawaban:

12

Ya ada. Saya akan menyarankan menggunakan Powershell karena menangani file Word dengan cukup baik. Saya pikir saya akan menjadi cara termudah.

Lebih lanjut tentang Powershell vs otomatisasi Word di sini: http://www.simple-talk.com/dotnet/.net-tools/com-automation-of-office-applications-via-powershell/

Saya telah menggali sedikit lebih dalam dan saya menemukan skrip PowerShell ini:

param([string]$docpath,[string]$htmlpath = $docpath)

$srcfiles = Get-ChildItem $docPath -filter "*.doc"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatFilteredHTML");
$word = new-object -comobject word.application
$word.Visible = $False

function saveas-filteredhtml
    {
        $opendoc = $word.documents.open($doc.FullName);
        $opendoc.saveas([ref]"$htmlpath\$doc.fullname.html", [ref]$saveFormat);
        $opendoc.close();
    }

ForEach ($doc in $srcfiles)
    {
        Write-Host "Processing :" $doc.FullName
        saveas-filteredhtml
        $doc = $null
    }

$word.quit();

Simpan sebagai .ps1 dan mulai dengan:

convertdoc-tohtml.ps1 -docpath "C:\Documents" -htmlpath "C:\Output"

Ini akan menyimpan semua file .doc dari direktori yang ditentukan, sebagai file html. Jadi saya punya file doc di mana saya memiliki H2SO4 Anda dengan subskrip dan setelah konversi powershell hasilnya adalah sebagai berikut:

<html>

<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=Generator content="Microsoft Word 14 (filtered)">
<style>
<!--
 /* Font Definitions */
 @font-face
    {font-family:Calibri;
    panose-1:2 15 5 2 2 2 4 3 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
    {margin-top:0in;
    margin-right:0in;
    margin-bottom:10.0pt;
    margin-left:0in;
    line-height:115%;
    font-size:11.0pt;
    font-family:"Calibri","sans-serif";}
.MsoChpDefault
    {font-family:"Calibri","sans-serif";}
.MsoPapDefault
    {margin-bottom:10.0pt;
    line-height:115%;}
@page WordSection1
    {size:8.5in 11.0in;
    margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
    {page:WordSection1;}
-->
</style>

</head>

<body lang=EN-US>

<div class=WordSection1>

<p class=MsoNormal><span lang=PL>H<sub>2</sub>SO<sub>4</sub></span></p>

</div>

</body>

</html>

Seperti yang Anda lihat, subskrip memiliki tag sendiri dalam HTML sehingga satu-satunya yang tersisa adalah mengurai file dalam bash atau c ++ untuk memotong dari tubuh ke / tubuh, ubah ke LATEX dan hapus sisa tag HTML setelahnya.

Kode dari http://blogs.technet.com/b/bshukla/archive/2011/09/27/3347395.aspx


Jadi saya telah mengembangkan parser di C ++ untuk mencari subscript HTML dan menggantinya dengan subscript LATEX.

Kode:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

 vector < vector <string> > parse( vector < vector <string> > vec, string filename )
{
        /*
                PARSES SPECIFIED FILE. EACH WORD SEPARATED AND
                PLACED IN VECTOR FIELD.

                REQUIRED INCLUDES:
                                #include <iostream>
                                #include <fstream>
                                #include <string>
                                #include <sstream>
                                #include <vector>

            EXPECTS: TWO DIMENTIONAL VECTOR
                     STRING WITH FILENAME
            RETURNS: TWO DIMENTIONAL VECTOR
                     vec[lines][words]
        */
        string vword;
        ifstream vfile;
        string tmp;

         // FILENAME CONVERSION FROM STING
        //  TO CHAR TABLE

        char cfilename[filename.length()+1];
        if( filename.length() < 126 )
        {
                for(int i = 0; i < filename.length(); i++)
                                cfilename[i] = filename[i];
                cfilename[filename.length()] = '\0';
        }
        else return vec;

         // OPENING FILE
        //
        vfile.open( cfilename );
        if (vfile.is_open())
        {
                while ( vfile.good() )
                {
                        getline( vfile, vword );
                        vector < string > vline;
                        vline.clear();

                        for (int i = 0; i < vword.length(); i++)
                        {
                                tmp = "";
                                 // PARSING CONTENT. OMITTING SPACES AND TABS
                                //
                                while (vword[i] != ' ' && vword[i] != ((char)9) && i < vword.length() )
                                        tmp += vword[i++];
                                if( tmp.length() > 0 ) vline.push_back(tmp);
                        }
                        if (!vline.empty())
                                vec.push_back(vline);
                }
                vfile.close();
        }
        else cout << "Unable to open file " << filename << ".\n";
        return vec;
}

int main()
{
        vector < vector < string > > vec;
        vec = parse( vec, "parse.html" );

        bool body = false;
        for (int i = 0; i < vec.size(); i++)
        {
                for (int j = 0; j < vec[i].size(); j++)
                {
                        if ( vec[i][j] == "<body") body=true;
                        if ( vec[i][j] == "</body>" ) body=false;
                        if ( body == true )
                        {
                                for ( int k=0; k < vec[i][j].size(); k++ )
                                {
                                        if (k+4 < vec[i][j].size() )
                                        {
                                                if (    vec[i][j][k]   == '<' &&
                                                        vec[i][j][k+1] == 's' &&
                                                        vec[i][j][k+2] == 'u' &&
                                                        vec[i][j][k+3] == 'b' &&
                                                        vec[i][j][k+4] == '>' )
                                                {

                                                        string tmp = "";
                                                        while (vec[i][j][k+5] != '<')
                                                        {
                                                                tmp+=vec[i][j][k+5];
                                                                k++;
                                                        }
                                                        tmp = "_{" + tmp + "}";
                                                        k=k+5+5;
                                                        cout << tmp << endl;;
                                                }
                                                else cout << vec[i][j][k];
                                        }
                                        else cout << vec[i][j][k];
                                }
                                cout << endl;
                        }
                }
        }
        return 0;
}

Untuk file html:

<html>

<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=Generator content="Microsoft Word 14 (filtered)">
<style>
<!--
 /* Font Definitions */
 @font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin-top:0in;
        margin-right:0in;
        margin-bottom:10.0pt;
        margin-left:0in;
        line-height:115%;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
.MsoChpDefault
        {font-family:"Calibri","sans-serif";}
.MsoPapDefault
        {margin-bottom:10.0pt;
        line-height:115%;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
-->
</style>

</head>

<body lang=EN-US>

<div class=WordSection1>

<p class=MsoNormal><span lang=PL>H<sub>2</sub>SO<sub>4</sub></span></p>

</div>

</body>

</html>

Outputnya adalah:

<body
lang=EN-US>
<div
class=WordSection1>
<p
class=MsoNormal><span
lang=PL>H_{2}
SO_{4}
</span></p>
</div>

Tentu saja ini tidak ideal, tetapi memperlakukan adalah sebagai bukti konsep.

mnmnc
sumber
3

Anda dapat mengekstrak xml langsung dari dokumen kantor apa pun yang 2007+. Ini dilakukan dengan cara berikut:

  1. ganti nama file dari .docx ke .zip
  2. ekstrak file menggunakan 7zip (atau program ekstraksi lainnya)
  3. Untuk konten dokumen yang sebenarnya, lihat di folder yang diekstrak di bawah wordsubfolder dan document.xmlfile. Itu harus mengandung semua konten dokumen.

masukkan deskripsi gambar di sini

Saya membuat dokumen sampel, dan di tag tubuh saya menemukan ini (perhatikan saya cepat-cepat menyatukannya, jadi pemformatannya mungkin sedikit salah):

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<w:body>
    -<w:p w:rsidRDefault="000E0C3A" w:rsidR="008B5DAA">
        -<w:r>
            <w:t xml:space="preserve">This </w:t>
        </w:r>
-       <w:r w:rsidRPr="000E0C3A">
            -<w:rPr>
                <w:vertAlign w:val="superscript"/>
            </w:rPr>
            <w:t>is</w:t>
        </w:r>
-       <w:r>
            <w:t xml:space="preserve"> a </w:t>
        </w:r>
            -<w:r w:rsidRPr="000E0C3A">
                -<w:rPr>
                    <w:vertAlign w:val="subscript"/>
                </w:rPr>
                <w:t>test</w:t>
            </w:r>
        -<w:r>
            <w:t>.</w:t>
        </w:r>
    </w:p>
</w:body>

Tampaknya <w:t>tag tersebut untuk teks, <w:rPr>adalah definisi font dan<w:p> paragraf baru.

Kata setara terlihat seperti ini:

masukkan deskripsi gambar di sini

James Mertz
sumber
2

Saya telah melihat pendekatan yang berbeda dari yang ditempuh oleh mnmnc.

Upaya saya untuk menyimpan dokumen Word uji sebagai HTML tidak berhasil. Saya telah menemukan di masa lalu bahwa Office menghasilkan HTML sangat penuh dengan sekam yang memilih bit yang Anda inginkan hampir mustahil. Saya telah menemukan itu menjadi kasus di sini. Saya juga punya masalah dengan persamaan. Word menyimpan persamaan sebagai gambar. Untuk setiap persamaan akan ada dua gambar satu dengan ekstensi WMZ dan satu dengan ekstensi GIF. Jika Anda menampilkan file html dengan Google Chrome, persamaannya terlihat OK tapi tidak bagus; penampilannya cocok dengan file GIF saat ditampilkan dengan tampilan gambar / alat edit yang dapat menangani gambar transparan. Jika Anda menampilkan file HTML dengan Internet Explorer, persamaannya terlihat sempurna.

Informasi tambahan

Saya seharusnya memasukkan informasi ini dalam jawaban asli.

Saya membuat dokumen Word kecil yang saya simpan sebagai Html. Tiga panel pada gambar di bawah ini menunjukkan dokumen Word asli, dokumen Html seperti yang ditampilkan oleh Microsoft Internet Explorer dan dokumen Html seperti yang ditampilkan oleh Google Chrome.

Kata asli, Html ditampilkan oleh IE dan HTML ditampilkan oleh Chrome

Seperti yang dijelaskan sebelumnya, perbedaan antara gambar IE dan Chrome adalah hasil dari persamaan yang disimpan dua kali, sekali dalam format WMZ dan sekali dalam format GIF. Html terlalu besar untuk ditampilkan di sini.

Html yang dibuat oleh makro adalah:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" 
                   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head><body>
<p>Some ordinary text.</p>
<p>H<sub>2</sub>SO<sub>4</sub>.</p>
<p>Abc &amp; def &gt; ghi &lt; jkl</p>
<p>x<sup>3</sup>+ x<sup>2</sup>+3x+4=0.</p><p></p>
<p><i>Equation</i>  </p>
<p>Mno</p>
<p><i>Equation</i></p>
</body></html>

Yang ditampilkan sebagai:

Html dibuat oleh makro seperti yang ditampilkan oleh IE

Saya belum mencoba untuk mengubah persamaan karena Kit Pengembangan Perangkat Lunak MathType gratis ternyata mencakup rutinitas yang dikonversi ke LaTex

Kode ini cukup mendasar sehingga tidak banyak komentar. Tanyakan apakah ada yang tidak jelas. Catatan: ini adalah versi yang disempurnakan dari kode asli.

Sub ConvertToHtml()

  Dim FileNum As Long
  Dim NumPendingCR As Long
  Dim objChr As Object
  Dim PathCrnt As String
  Dim rng As Word.Range
  Dim WithinPara As Boolean
  Dim WithinSuper As Boolean
  Dim WithinSub As Boolean

  FileNum = FreeFile
  PathCrnt = ActiveDocument.Path
  Open PathCrnt & "\TestWord.html" For Output Access Write Lock Write As #FileNum

  Print #FileNum, "<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Frameset//EN""" & _
                  " ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"">" & _
                  vbCr & vbLf & "<html xmlns=""http://www.w3.org/1999/xhtml"" " & _
                  "xml:lang=""en"" lang=""en"">" & vbCr & vbLf & _
                  "<head><meta http-equiv=""Content-Type"" content=""text/html; " _
                  & "charset=utf-8"" />" & vbCr & vbLf & "</head><body>"

  For Each rng In ActiveDocument.StoryRanges

    NumPendingCR = 0
    WithinPara = False
    WithinSub = False
    WithinSuper = False

    Do While Not (rng Is Nothing)
      For Each objChr In rng.Characters
        If objChr.Font.Superscript Then
          If Not WithinSuper Then
            ' Start of superscript
            Print #FileNum, "<sup>";
            WithinSuper = True
          End If
        ElseIf WithinSuper Then
          ' End of superscript
          Print #FileNum, "</sup>";
          WithinSuper = False
        End If
        If objChr.Font.Subscript Then
          If Not WithinSub Then
            ' Start of subscript
            Print #FileNum, "<sub>";
            WithinSub = True
          End If
        ElseIf WithinSub Then
          ' End of subscript
          Print #FileNum, "</sub>";
          WithinSub = False
          End If
          Select Case objChr
            Case vbCr
              NumPendingCR = NumPendingCR + 1
            Case "&"
              Print #FileNum, CheckPara(NumPendingCR, WithinPara) & "&amp;";
            Case "<"
              Print #FileNum, CheckPara(NumPendingCR, WithinPara) & "&lt;";
            Case ">"
              Print #FileNum, CheckPara(NumPendingCR, WithinPara) & "&gt;";
            Case Chr(1)
              Print #FileNum, CheckPara(NumPendingCR, WithinPara) & "<i>Equation</i>";
            Case Else
              Print #FileNum, CheckPara(NumPendingCR, WithinPara) & objChr;
          End Select
      Next
      Set rng = rng.NextStoryRange
    Loop
  Next

  If WithinPara Then
    Print #FileNum, "</p>";
    withpara = False
  End If

  Print #FileNum, vbCr & vbLf & "</body></html>"

  Close FileNum

End Sub
Function CheckPara(ByRef NumPendingCR As Long, _
                   ByRef WithinPara As Boolean) As String

  ' Have a character to output.  Check paragraph status, return
  ' necessary commands and adjust NumPendingCR and WithinPara.

  Dim RtnValue As String

  RtnValue = ""

  If NumPendingCR = 0 Then
    If Not WithinPara Then
      CheckPara = "<p>"
      WithinPara = True
    Else
      CheckPara = ""
    End If
    Exit Function
  End If

  If WithinPara And (NumPendingCR > 0) Then
    ' Terminate paragraph
    RtnValue = "</p>"
    NumPendingCR = NumPendingCR - 1
    WithinPara = False
  End If
  Do While NumPendingCR > 1
    ' Replace each pair of CRs with an empty paragraph
    RtnValue = RtnValue & "<p></p>"
    NumPendingCR = NumPendingCR - 2
  Loop
  RtnValue = RtnValue & vbCr & vbLf & "<p>"
  WithinPara = True
  NumPendingCR = 0

  CheckPara = RtnValue

End Function
Tony Dallimore
sumber
Kerja bagus. Apakah ini akan berfungsi untuk banyak file atau Anda harus meletakkannya di dalam file yang ingin Anda konversi?
mnmnc
@ mnm. Terima kasih. Saya pikir solusi Anda adalah kesan walaupun mungkin jelas bahwa saya tidak percaya solusi yang dimulai dengan Microsoft Html akan berfungsi. Sebagai hasil dari pertanyaan Stack Overflow, saya berupaya mengonversikan Excel ke Html karena Microsoft's PublishingObjects membuat Html tidak dapat diterima oleh kebanyakan (semua?) Smartphone. Saya memiliki sedikit pengalaman dengan Word VBA; Saya paling baik dengan Excel dan Outlook VBA dan saya terbiasa dengan Acess VBA. Ini semua memungkinkan makro dalam satu file untuk mengakses file lain jadi saya yakin hal yang sama berlaku untuk Word.
Tony Dallimore
0

Cara paling sederhana untuk melakukan ini adalah hanya baris berikut di VBA:

Sub testing()
With ActiveDocument.Content.Find
 .ClearFormatting
 .Format = True
 .Font.Superscript = True
 .Execute Forward:=True
End With

End Sub

Ini akan menemukan semua teks superscript. Jika Anda ingin melakukan sesuatu dengannya, cukup masukkan ke dalam metode. Misalnya, untuk menemukan kata "super" dalam superscript, dan mengubahnya menjadi "super found" gunakan:

Sub testing()

With ActiveDocument.Content.Find
 .ClearFormatting
 .Format = True
 .Font.Superscript = True
 .Execute Forward:=True, Replace:=wdReplaceAll, _
 FindText:="super", ReplaceWith:="super found"
End With

End Sub
Soando
sumber