Cách lặp lại theo chương trình thông qua các chỉ mục, siêu ký tự và phương trình được tìm thấy trong tài liệu Word


12

Tôi có một vài tài liệu Word, mỗi tài liệu chứa vài trăm trang dữ liệu khoa học bao gồm:

  • Công thức hóa học (H2SO4 với tất cả các chỉ số & siêu ký tự phù hợp)
  • Số khoa học (số mũ được định dạng bằng siêu ký tự)
  • Rất nhiều phương trình toán học. Viết bằng trình soạn thảo phương trình toán học trong Word.

Vấn đề là, lưu trữ dữ liệu này trong Word không hiệu quả đối với chúng tôi. Vì vậy, chúng tôi muốn lưu trữ tất cả thông tin này trong cơ sở dữ liệu (MySQL). Chúng tôi muốn chuyển đổi định dạng sang LaTex.

Có cách nào lặp đi lặp lại qua tất cả các bảng con, siêu ký tự và phương trình trong tài liệu Word bằng VBA không?


Bạn đã nghĩ về việc trích xuất dữ liệu xml từ trong tài liệu tự nó? Tất cả Microsoft Documents 2007+ (.docx) về cơ bản là các tệp xml được nén. Bạn có thể truy xuất những người sử dụng trình phân tích cú pháp xml.
James Mertz

quá dài để đăng bình luận, vì vậy tôi đã thêm vào như một câu trả lời.
James Mertz

Câu trả lời:


12

Có, có. Tôi sẽ sử dụng Powershell vì nó xử lý các tệp Word khá tốt. Tôi nghĩ rằng tôi sẽ là cách dễ nhất.

Thông tin thêm về tự động hóa Powershell vs Word tại đây: http://www.simple-talk.com/dotnet/.net-tools/com-automation-of-office-appluggest-via-powershell/

Tôi đã đào sâu hơn một chút và tôi tìm thấy kịch bản powershell này:

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

Lưu nó dưới dạng .ps1 và bắt đầu với:

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

Nó sẽ lưu tất cả các tệp .doc từ thư mục được chỉ định, dưới dạng các tệp html. Vì vậy, tôi có một tệp tài liệu trong đó tôi có H2SO4 của bạn với các mục con và sau khi hội tụ powershell, kết quả đầu ra như sau:

<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>

Như bạn có thể thấy các mục con có các thẻ riêng trong HTML, do đó, điều duy nhất còn lại là phân tích tệp trong bash hoặc c ++ để cắt từ phần thân sang / phần thân, thay đổi thành LATEX và xóa phần còn lại của các thẻ HTML sau đó.

Mã từ http://bloss.technet.com/b/bshukla/archive/2011/09/27/3347395.aspx


Vì vậy, tôi đã phát triển một trình phân tích cú pháp trong C ++ để tìm kiếm chỉ mục HTML và thay thế nó bằng đăng ký LATEX.

Mật mã:

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

Đối với tệp 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>

Đầu ra là:

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

Tất nhiên đó không phải là lý tưởng, nhưng coi như là bằng chứng của khái niệm.


3

Bạn có thể trích xuất xml trực tiếp từ bất kỳ tài liệu văn phòng nào trong năm 2007+. Điều này được thực hiện theo cách sau:

  1. đổi tên tập tin từ .docx thành .zip
  2. giải nén tập tin bằng 7zip (hoặc một số chương trình giải nén khác)
  3. Đối với nội dung thực tế của tài liệu, hãy tìm trong thư mục giải wordnén dưới thư mục con và document.xmltệp. Điều đó nên chứa tất cả nội dung của tài liệu.

nhập mô tả hình ảnh ở đây

Tôi đã tạo một tài liệu mẫu và trong các thẻ body tôi đã tìm thấy tài liệu này (lưu ý tôi nhanh chóng kết hợp tài liệu này với nhau, vì vậy định dạng có thể hơi sai):

<?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>

Dường như <w:t>thẻ dành cho văn bản <w:rPr>là định nghĩa của phông chữ và <w:p>là một đoạn mới.

Từ tương đương trông như thế này:

nhập mô tả hình ảnh ở đây


2

Tôi đã xem xét một cách tiếp cận khác với phương pháp mà mnmnc theo đuổi.

Những nỗ lực của tôi để lưu tài liệu Word thử nghiệm vì HTML không thành công. Trước đây tôi đã phát hiện ra rằng HTML do Office tạo ra có quá nhiều trò đùa đến nỗi việc chọn ra các bit bạn muốn là gần như không thể. Tôi đã tìm thấy rằng đó là trường hợp ở đây. Tôi cũng đã có một vấn đề với phương trình. Word lưu phương trình dưới dạng hình ảnh. Đối với mỗi phương trình sẽ có hai hình ảnh một phần mở rộng WMZ và một hình ảnh có phần mở rộng GIF. Nếu bạn hiển thị tệp html bằng Google Chrome, các phương trình có vẻ ổn nhưng không tuyệt vời; giao diện phù hợp với tệp GIF khi được hiển thị với công cụ chỉnh sửa / hiển thị hình ảnh có thể xử lý hình ảnh trong suốt. Nếu bạn hiển thị tệp HTML bằng Internet Explorer, các phương trình sẽ hoàn hảo.

Thông tin thêm

Tôi nên có thông tin này trong câu trả lời ban đầu.

Tôi đã tạo một tài liệu Word nhỏ mà tôi đã lưu dưới dạng Html. Ba bảng trong hình ảnh bên dưới hiển thị tài liệu Word gốc, tài liệu Html như được hiển thị bởi Microsoft Internet Explorer và tài liệu Html như được hiển thị bởi Google Chrome.

Từ gốc, Html được hiển thị bởi IE và HTML được hiển thị bởi Chrome

Như đã giải thích trước đó, sự khác biệt giữa hình ảnh IE và Chrome là kết quả của các phương trình được lưu hai lần, một lần ở định dạng WMZ và một lần ở định dạng GIF. Html quá lớn để hiển thị ở đây.

Html được tạo bởi macro là:

<!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>

Hiển thị dưới dạng:

Html được tạo bởi macro như được hiển thị bởi IE

Tôi đã không cố gắng chuyển đổi các phương trình vì Bộ công cụ phát triển phần mềm MathType miễn phí rõ ràng bao gồm các thói quen chuyển đổi sang LaTex

Mã này khá cơ bản nên không có nhiều bình luận. Hỏi xem có gì không rõ ràng không. Lưu ý: đây là phiên bản cải tiến của mã gốc.

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

Công việc tuyệt vời Nó sẽ hoạt động cho nhiều tệp hay bạn phải đặt nó trong tệp bạn muốn chuyển đổi?
mnmnc

@mnmnc. Cảm ơn bạn. Tôi nghĩ rằng giải pháp của bạn là ấn tượng mặc dù có thể rõ ràng rằng tôi không tin rằng một giải pháp bắt đầu với Microsoft Html sẽ hoạt động. Do câu hỏi về Stack Overflow, tôi đang nghiên cứu chuyển đổi Excel sang Html vì PublishObjects của Microsoft tạo ra Html không thể chấp nhận được đối với hầu hết (tất cả?) Điện thoại thông minh. Tôi có ít kinh nghiệm với Word VBA; Tôi giỏi nhất với Excel và Outlook VBA và tôi đã từng rất tốt với Acess VBA. Tất cả đều cho phép một macro trong một tệp truy cập vào các tệp khác vì vậy tôi chắc chắn điều tương tự cũng đúng với Word.
Tony Dall Morph

0

Cách đơn giản nhất để làm điều này chỉ là các dòng sau trong VBA:

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

End Sub

Điều này sẽ tìm thấy tất cả các văn bản siêu. Nếu bạn muốn làm một cái gì đó với nó, chỉ cần chèn nó vào phương thức. Ví dụ: để tìm từ "siêu" trong một siêu ký tự và biến nó thành "siêu tìm thấy" sử dụng:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.