วิธีการวนซ้ำโดยทางโปรแกรมผ่านตัวห้อยตัวยกและสมการที่พบในเอกสาร Word


12

ฉันมีเอกสาร Word สองสามชุดแต่ละชุดมีข้อมูลทางวิทยาศาสตร์สองสามร้อยหน้าซึ่งประกอบด้วย:

  • สูตรทางเคมี (H2SO4 ที่มีตัวห้อยและตัวยกที่เหมาะสมทั้งหมด)
  • ตัวเลขทางวิทยาศาสตร์ (เลขชี้กำลังจัดรูปแบบโดยใช้ตัวยก)
  • สมการทางคณิตศาสตร์มากมาย เขียนโดยใช้เครื่องมือแก้ไขสมการทางคณิตศาสตร์ใน Word

ปัญหาคือการจัดเก็บข้อมูลนี้ใน Word นั้นไม่มีประสิทธิภาพสำหรับเรา ดังนั้นเราต้องการเก็บข้อมูลทั้งหมดนี้ไว้ในฐานข้อมูล (MySQL) เราต้องการแปลงการจัดรูปแบบเป็น LaTex

มีวิธีใดบ้างที่จะทำซ้ำผ่านตัวย่อ, ตัวยกและสมการทั้งหมดในเอกสาร Word โดยใช้ VBA?


คุณคิดว่าจะดึงข้อมูล xml จากภายในเอกสารด้วยตนเองหรือไม่? Microsoft Documents 2007+ (.docx) ทั้งหมดเป็นไฟล์ xml ที่ถูกบีบอัด คุณสามารถดึงข้อมูลเหล่านั้นโดยใช้ตัวแยกวิเคราะห์ xml
James Mertz

มันยาวเกินไปที่จะโพสต์เป็นความคิดเห็นดังนั้นฉันจึงเพิ่มเป็นคำตอบ
James Mertz

คำตอบ:


12

ใช่แล้ว ฉันอยากใช้ Powershell เพราะมันจัดการไฟล์ Word ได้ค่อนข้างดี ฉันคิดว่าฉันจะเป็นวิธีที่ง่ายที่สุด

ข้อมูลเพิ่มเติมเกี่ยวกับ Powershell vs Word automation ได้ที่นี่: http://www.simple-talk.com/dotnet/.net-tools/com-automation-of-office-applications-via-powershell/

ฉันขุดลึกลงไปอีกเล็กน้อยและฉันพบสคริปต์ PowerShell นี้:

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

บันทึกเป็น. ps1 และเริ่มด้วย:

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

มันจะบันทึกไฟล์. doc ทั้งหมดจากไดเรกทอรีที่ระบุเป็นไฟล์ html ดังนั้นฉันมีไฟล์เอกสารที่ฉันมี H2SO4 ของคุณด้วยตัวห้อยและหลังจากการแปลง PowerShell ผลลัพธ์จะเป็นดังนี้:

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

ในขณะที่คุณสามารถเห็นตัวห้อยมีแท็กของตัวเองใน HTML ดังนั้นสิ่งเดียวที่เหลือคือการแยกไฟล์ใน bash หรือ c ++ เพื่อตัดจาก body เป็น / body เปลี่ยนเป็น LATEX และลบแท็ก HTML ที่เหลือหลังจากนั้น

รหัสจากhttp://blogs.technet.com/b/bshukla/archive/2011/09/27/3347395.aspx


ดังนั้นฉันได้พัฒนา parser ใน C ++ เพื่อค้นหาตัวห้อย HTML และแทนที่ด้วยตัวห้อย LATEX

รหัส:

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

สำหรับไฟล์ 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>

ผลลัพธ์คือ:

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

แน่นอนว่ามันไม่เหมาะ แต่การรักษาถือเป็นข้อพิสูจน์แนวคิด


3

คุณสามารถแยก xml ได้โดยตรงจากเอกสาร office ใด ๆ ที่เป็น 2007+ สิ่งนี้ทำในรูปแบบต่อไปนี้:

  1. เปลี่ยนชื่อไฟล์จาก. docx เป็น. zip
  2. แตกไฟล์โดยใช้ 7zip (หรือโปรแกรมแยกอื่น ๆ )
  3. สำหรับเนื้อหาที่แท้จริงของเอกสารดูในโฟลเดอร์ที่แยกภายใต้wordโฟลเดอร์ย่อยและdocument.xmlไฟล์ ที่ควรมีเนื้อหาทั้งหมดของเอกสาร

ป้อนคำอธิบายรูปภาพที่นี่

ฉันสร้างเอกสารตัวอย่างและในแท็ก body ฉันพบสิ่งนี้ (โปรดทราบว่าฉันรวมสิ่งนี้เข้าด้วยกันอย่างรวดเร็วดังนั้นการจัดรูปแบบอาจเล็กน้อย)

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

ปรากฏว่า<w:t>แท็กเป็นข้อความที่<w:rPr>เป็นคำจำกัดความของแบบอักษรและ<w:p>เป็นย่อหน้าใหม่

คำเทียบเท่ามีลักษณะเช่นนี้:

ป้อนคำอธิบายรูปภาพที่นี่


2

ฉันได้ดูวิธีที่แตกต่างจากที่ติดตามโดย mnmnc

ความพยายามในการบันทึกเอกสารทดสอบ Word เป็น HTML ไม่ประสบความสำเร็จ ฉันพบว่าในอดีตที่ Office สร้าง HTML นั้นเต็มไปด้วยแกลบที่หยิบเอาบิตที่คุณต้องการใกล้จะเป็นไปไม่ได้ ฉันได้พบว่าเป็นกรณีที่นี่ ฉันยังมีปัญหากับสมการ Word บันทึกสมการเป็นภาพ สำหรับแต่ละสมการจะมีสองภาพหนึ่งภาพที่มีนามสกุล WMZ และอีกหนึ่งภาพที่มีนามสกุล GIF หากคุณแสดงไฟล์ html ด้วย Google Chrome สมการจะดูดี แต่ก็ไม่ได้ยอดเยี่ยม ลักษณะที่ปรากฏตรงกับไฟล์ GIF เมื่อแสดงด้วยเครื่องมือแสดง / แก้ไขภาพที่สามารถจัดการภาพโปร่งใส หากคุณแสดงไฟล์ HTML ด้วย Internet Explorer สมการจะดูสมบูรณ์แบบ

ข้อมูลเพิ่มเติม

ฉันควรจะรวมข้อมูลนี้ในคำตอบเดิม

ฉันสร้างเอกสาร Word ขนาดเล็กซึ่งฉันบันทึกเป็น Html พาเนลทั้งสามในรูปภาพด้านล่างแสดงเอกสาร Word ต้นฉบับเอกสาร Html ที่แสดงโดย Microsoft Internet Explorer และเอกสาร Html ตามที่แสดงโดย Google Chrome

คำดั้งเดิม, Html ที่แสดงโดย IE และ HTML ที่แสดงโดย Chrome

ดังที่อธิบายไว้ก่อนหน้านี้ความแตกต่างระหว่างรูปภาพ IE และ Chrome คือผลลัพธ์ของสมการที่ถูกบันทึกสองครั้งหนึ่งครั้งในรูปแบบ WMZ และอีกครั้งในรูปแบบ GIF Html ใหญ่เกินไปที่จะแสดงที่นี่

Html ที่สร้างโดยแมโครคือ:

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

ซึ่งแสดงเป็น:

Html ที่สร้างขึ้นโดยแมโครตามที่แสดงโดย IE

ฉันไม่ได้พยายามแปลงสมการเนื่องจากชุดพัฒนาซอฟต์แวร์ MathTypeฟรีมีงานประจำที่แปลงเป็น LaTex

รหัสนั้นค่อนข้างธรรมดาดังนั้นมีคอมเม้นไม่มากนัก ถามว่ามีอะไรไม่ชัดเจน หมายเหตุ: นี่เป็นรุ่นปรับปรุงของรหัสต้นฉบับ

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

การทำงานที่ดี. มันจะใช้งานได้กับหลายไฟล์หรือคุณต้องวางไว้ในไฟล์ที่คุณต้องการแปลง?
mnmnc

@mnmnc ขอขอบคุณ. ฉันคิดว่าโซลูชันของคุณเป็นที่ประทับใจแม้ว่าอาจจะชัดเจนว่าฉันไม่เชื่อว่าโซลูชันที่เริ่มต้นด้วย Microsoft Html จะทำงานได้ จากคำถาม Stack Overflow ฉันกำลังทำงานเพื่อแปลง Excel เป็น Html เนื่องจาก PublishObjects ของ Microsoft สร้าง Html ที่ยอมรับไม่ได้กับสมาร์ทโฟนส่วนใหญ่ (ทั้งหมด?) ฉันมีประสบการณ์เล็กน้อยกับ Word VBA ฉันดีที่สุดกับ Excel และ Outlook VBA และฉันเคยดีกับ Acess VBA ทั้งหมดนี้อนุญาตให้มาโครในไฟล์เดียวสามารถเข้าถึงไฟล์อื่น ๆ ได้ดังนั้นฉันจึงมั่นใจว่าเป็นจริงสำหรับ Word
Tony Dallimore

0

วิธีที่ง่ายที่สุดในการทำเช่นนี้เป็นเพียงบรรทัดต่อไปนี้ใน VBA:

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

End Sub

นี่จะค้นหาข้อความที่ยกมาทั้งหมด หากคุณต้องการทำอะไรกับมันเพียงแค่แทรกมันเข้าไปในวิธีการ ตัวอย่างเช่นหากต้องการค้นหาคำว่า "super" ในตัวยกและเปลี่ยนเป็นคำว่า "super found" use:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.