Word belgesinde bulunan abonelikler, üst simgeler ve denklemler aracılığıyla programlı olarak yineleme


12

Her biri içeren birkaç yüz sayfa bilimsel veri içeren birkaç Word belgesim var:

  • Kimyasal formüller (tüm uygun aboneliklere ve üstyazılara sahip H2SO4)
  • Bilimsel sayılar (üst simgeler kullanılarak biçimlendirilmiş üsler)
  • Birçok Matematiksel Denklem. Word'de matematiksel denklem düzenleyicisi kullanılarak yazılmıştır.

Sorun şu ki, bu verileri Word'de saklamak bizim için verimli değil. Bu yüzden tüm bu bilgileri bir veritabanında (MySQL) saklamak istiyoruz. Biçimlendirmeyi LaTex'e dönüştürmek istiyoruz.

VBA kullanarak bir Word belgesindeki tüm altyazıları, üstyazıları ve denklemleri yinelemenin bir yolu var mı?


Kendi kendine belgenin içinden xml verilerini ayıklamayı düşündünüz mü? Tüm Microsoft Documents 2007+ (.docx) temel olarak sıkıştırılmış xml dosyalarıdır. Bir xml ayrıştırıcı kullanarak bunları alabilirsiniz.
James Mertz

yorum olarak yayınlamak çok uzun sürdü, bu yüzden cevap olarak ekledim.
James Mertz

Yanıtlar:


12

Evet var. Word dosyalarını oldukça iyi idare ettiği için Powershell'i kullanmaktan hoşlanıyorum. Bence en kolay yol olacağım.

Powershell ve Word otomasyonu hakkında daha fazla bilgiyi burada bulabilirsiniz: http://www.simple-talk.com/dotnet/.net-tools/com-automation-of-office-applications-via-powershell/

Biraz daha derine kazdım ve bu powershell betiğini buldum:

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 olarak kaydedin ve şunlarla başlayın:

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

Belirtilen dizindeki tüm .doc dosyasını html dosyaları olarak kaydeder. Yani ben aboneler ile H2SO4 sahip bir doc dosyası var ve powershell dönüşüm sonra çıktı aşağıdaki gibidir:

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

Gördüğünüz gibi, abonelerin HTML'de kendi etiketleri var, bu yüzden kalan tek şey dosyayı gövdeden / gövdeye kesmek için bash veya c ++ 'da ayrıştırmak, LATEX olarak değiştirmek ve daha sonra kalan HTML etiketlerini kaldırmaktır.

Http://blogs.technet.com/b/bshukla/archive/2011/09/27/3347395.aspx adresinden kod


Bu yüzden HTML aboneliği aramak ve LATEX aboneliği ile değiştirmek için C ++ 'da bir ayrıştırıcı geliştirdim.

Kod:

#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 dosyası için:

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

Çıktı:

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

Tabii ki ideal değil, ama tedavi kavramın kanıtıdır.


3

XML'yi doğrudan 2007+ olan herhangi bir ofis belgesinden ayıklayabilirsiniz. Bu aşağıdaki şekilde yapılır:

  1. dosyayı .docx yerine .zip olarak yeniden adlandırın
  2. 7zip (veya başka bir çıkarma programı) kullanarak dosyayı ayıklayın
  3. Belgenin asıl içeriği için wordalt klasörün ve document.xmldosyanın altındaki çıkarılan klasöre bakın . Bu belgenin tüm içeriğini içermelidir.

resim açıklamasını buraya girin

Örnek bir belge oluşturdum ve gövde etiketlerinde bunu buldum (bunu hızlı bir şekilde bir araya getirdim, bu yüzden biçimlendirme biraz kapalı olabilir):

<?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>Etiketin metin için <w:rPr>olduğu, yazı tipinin tanımı ve <w:p>yeni bir paragraf olduğu anlaşılıyor .

Eşdeğer kelime şuna benzer:

resim açıklamasını buraya girin


2

Mnmnc'nin izlediğinden farklı bir yaklaşıma bakıyorum.

Test Word belgesini HTML olarak kaydetme girişimlerim başarılı olmadı. Geçmişte, Office tarafından oluşturulan HTML'nin çok fazla samanla dolu olduğunu ve istediğiniz bitleri seçmenin imkansız olduğunu buldum. Burada böyle olduğunu gördüm. Ayrıca denklemlerle ilgili bir sorunum var. Word, denklemleri görüntüler olarak kaydeder. Her denklem için biri WMZ uzantılı, diğeri GIF uzantılı iki görüntü olacaktır. Html dosyasını Google Chrome ile görüntülerseniz, denklemler iyi görünür ancak harika değildir; saydam görüntüleri işleyebilen bir görüntü görüntüleme / düzenleme aracıyla görüntülendiğinde görünüm GIF dosyasıyla eşleşir. HTML dosyasını Internet Explorer ile görüntülerseniz, denklemler mükemmel görünür.

Ek bilgi

Bu bilgiyi orijinal cevaba eklemeliydim.

Html olarak kaydettiğim küçük bir Word belgesi oluşturdum. Aşağıdaki görüntüdeki üç panel orijinal Word belgesini, Microsoft Internet Explorer tarafından görüntülenen Html belgesini ve Google Chrome tarafından görüntülenen Html belgesini göstermektedir.

Orijinal kelime, IE tarafından görüntülenen Html ve Chrome tarafından görüntülenen HTML

Daha önce açıklandığı gibi, IE ve Chrome görüntüleri arasındaki fark, denklemlerin bir kez WMZ biçiminde ve bir kez GIF biçiminde kaydedilmesinin sonucudur. Html burada gösterilemeyecek kadar büyük.

Makro tarafından oluşturulan 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>

Hangi olarak görüntülenir:

IE tarafından gösterildiği gibi makro tarafından oluşturulan html

Ücretsiz MathType Yazılım Geliştirme Kiti görünüşte LaTex dönüştürmek rutinleri içerdiğinden denklemleri dönüştürmeye çalışmadım

Kod oldukça basit yani pek çok yorum. Net olmayan bir şey olup olmadığını sorun. Not: Bu, orijinal kodun geliştirilmiş bir sürümüdür.

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

Harika iş. Birden fazla dosya için çalışır mı yoksa dönüştürmek istediğiniz dosyanın içine yerleştirmeniz mi gerekiyor?
mnmnc

@mnmnc. Teşekkür ederim. Herhalde Microsoft Html ile başlayan bir çözümün işe yarayacağına inanmadığım açık olsa da, çözümünüz bir izlenim. Yığın Taşması sorusunun bir sonucu olarak, Microsoft'un PublishObjects çoğu (tüm?) Akıllı telefon için kabul edilemez Html oluşturduğundan Excel'i Html'e dönüştürmeye çalışıyorum. Word VBA ile ilgili çok az deneyimim var; Excel ve Outlook VBA ile en iyisiyim ve eskiden Acess VBA ile iyiydim. Bunların hepsi bir dosyadaki bir makro diğer dosyalara erişmek için izin verir, bu yüzden aynı Word için doğru olduğundan eminim.
Tony Dallimore

0

Bunu yapmanın en basit yolu VBA'da sadece aşağıdaki satırlardır:

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

End Sub

Bu, tüm üstteki metni bulur. Bununla bir şey yapmak istiyorsanız, sadece yönteme ekleyin. Örneğin, bir üst simge içinde "süper" kelimesini bulmak ve "süper bulunan" a dönüştürmek için şunu kullanın:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.