скопируйте содержание документа Word, не используя буфер обмена (VBA)

Вот функция barebone, которую я придумал, которая имеет только AWS Javascript SDK в качестве зависимости. Вначале я ошибся в том, что Base 64 кодировал RawMessage.Data, но AWS SDK уже позаботился об этом.

Пустые строки \n также важны.

const sendRawEmail = async () => {

    // Set up from_name, from_email, to, subject, message_id, plain_text, html and configuration_set variables from database or manually

    var date = new Date();

    var boundary = `----=_Part${ Math.random().toString().substr( 2 ) }`;

    var rawMessage = [
        `From: "${ from_name }" <${ from_email }>`, // Can be just the email as well without <>
        `To: ${ to }`,
        `Subject: ${ subject }`,
        `MIME-Version: 1.0`,
        `Message-ID: <${ message_id }@eu-west-1.amazonses.com>`, // Will be replaced by SES
        `Date: ${ formatDate( date ) }`, // Will be replaced by SES
        `Return-Path: <${ message_id }@eu-west-1.amazonses.com>`, // Will be replaced by SES
        `Content-Type: multipart/alternative; boundary="${ boundary }"`, // For sending both plaintext & html content
        // ... you can add more headers here as decribed in https://docs.aws.amazon.com/ses/latest/DeveloperGuide/header-fields.html
        `\n`,
        `--${ boundary }`,
        `Content-Type: text/plain; charset=UTF-8`,
        `Content-Transfer-Encoding: 7bit`,
        `\n`,
        plain_text,
        `--${ boundary }`,
        `Content-Type: text/html; charset=UTF-8`,
        `Content-Transfer-Encoding: 7bit`,
        `\n`,
        html,
        `\n`,
        `--${ boundary }--`
    ]

    // Send the actual email
    await ses.sendRawEmail( {
        Destinations: [
            to
        ],
        RawMessage: {
            Data: rawMessage.join( '\n' )
        },
        Source: from_email, // Must be verified within AWS SES
        ConfigurationSetName: configuration_set, // optional AWS SES configuration set for open & click tracking
        Tags: [
            // ... optional email tags
        ]

    } ).promise();

}

Это служебные методы для форматирования заголовка даты. Вы также можете использовать библиотеку moment, например, moment().format('ddd, DD MMM YYYY HH:MM:SS ZZ');, но это не имеет значения, поскольку заголовок даты все равно перезаписывается AWS SES.

// Outputs timezone offset in format ZZ
const getOffset = ( date ) => {

    var offset          = - date.getTimezoneOffset();
    var offsetHours     = Math.abs( Math.floor( offset / 60 ) );
    var offsetMinutes   = Math.abs( offset ) - offsetHours * 60;

    var offsetSign      = ( offset > 0 ) ? '+' : '-';

    return offsetSign + ( '0' + offsetHours ).slice( -2 ) + ( '0' + offsetMinutes ).slice( -2 );

}

// Outputs two digit inputs with leading zero
const leadingZero = ( input ) => ( '0' + input ).slice( -2 );

// Formats date in ddd, DD MMM YYYY HH:MM:SS ZZ
const formatDate = ( date ) => {

    var weekdays = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ];

    var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];

    var weekday = weekdays[ date.getDay() ];

    var day = leadingZero( date.getDate() );

    var month = months[ date.getMonth() ];

    var year = date.getFullYear();

    var hour = leadingZero( date.getHours() );

    var minute = leadingZero( date.getMinutes() );

    var second = leadingZero( date.getSeconds() );

    var offset = getOffset( date );

    return `${ weekday }, ${ day } ${ month } ${ year } ${ hour }:${ minute }:${ second } ${ offset }`;

}

6
задан shruti1810 27 May 2015 в 09:45
поделиться

2 ответа

Я наконец разрешил копировать пословно. FormattedText, казалось, работал довольно хорошо до последнего слова (некоторое специальное предложение (очевидно) символы), куда внезапно ячейка, которую я просто заполнил скопированным содержанием, пойдет пробел. Когда я увеличил число ячеек, другие ошибки времени выполнения откроются, как Ваша таблица был поврежден, и другие неоднозначные. Так или иначе исходная ячейка, с которой я копировал всегда, казалось, имела эти специфические символы в конце с кодами ASCII 13 и 7. Я знаю что 13 средств, но 7? Так или иначе я решил скопировать все кроме этого последнего знака с кодом 7. Это, кажется, работает хорошо. И форматирование и поля копируется также. В любом случае целая история доказала мне для еще раз, что программирование в VBA является главным образом эмпирическим размещением. Вы никогда не уверены, когда что-то могло бы повредиться.. если я не пропускаю обновление на некоторых решающих понятиях..

Вот блоки кода, который я использовал. Идея состоит в том, что сначала у нас есть документ с синглом 1x1 таблица ячейки с некоторым содержанием обогащенного текста. В первой части кода (в макросе) я умножаю ячейки:

Dim cur_width As Integer, i As Integer, max_cells As Integer, cur_row As Integer
Dim origin_width As Integer
   If ActiveDocument.Tables.Count = 1 _
      And ActiveDocument.Tables(1).Rows.Count = 1 _
      And ActiveDocument.Tables(1).Columns.Count = 1 _
   Then
      max_cells = 7   ' how many times we are going to "clone" the original content
      i = 2           ' current cell count - starting from 2 since the cell with the original content is cell number 1
      cur_width = -1  ' current width
      cur_row = 1     ' current row count
      origin_width = ActiveDocument.Tables(1).Rows(1).Cells(1).Width

      ' loop for each row
      While i <= max_cells

          ' adjust current width
          If cur_row = 1 Then
             cur_width = origin_width
          Else
             cur_width = 0
          End If

          ' loop for each cell - as long as we have space, add cells horizontally 
          While i <= max_cells And cur_width + origin_width < ActiveDocument.PageSetup.PageWidth 
              Dim col As Integer

              ' \ returns floor() of the result
              col = i \ ActiveDocument.Tables(1).Rows.Count 

              // 'add cell, if it is not already created (which happens when we add rows)
              If ActiveDocument.Tables(1).Rows(cur_row).Cells.Count < col Then
                 ActiveDocument.Tables(1).Rows(cur_row).Cells.Add
              End If

              // 'adjust new cell width (probably unnecessary
              With ActiveDocument.Tables(1).Rows(cur_row).Cells(col)
                .Width = origin_width
              End With

              // 'keep track of the current width
              cur_width = cur_width + origin_width
              i = i + 1
          Wend

          ' when we don't have any horizontal space left, add row
          If i <= max_cells Then
            ActiveDocument.Tables(1).Rows.Add
            cur_row = cur_row + 1
          End If

      Wend
   End If

Во второй части макроса я заполняю каждую пустую ячейку с содержанием первой ячейки:

   ' duplicate the contents of the first cell to other cells
   Dim r As Row
   Dim c As Cell
   Dim b As Boolean
   Dim w As Range
   Dim rn As Range
   b = False
   i = 1

   For Each r In ActiveDocument.Tables(1).Rows
       For Each c In r.Cells
            If i <= max_cells Then
                // ' don't copy first cell to itself
                If b = True Then

                    ' copy everything word by word
                    For Each w In ActiveDocument.Tables(1).Rows(1).Cells(1).Range.Words

                        ' get the last bit of formatted text in the destination cell, as range
                        ' do it first by getting the whole range of the cell, then collapsing it
                        ' so that it is now the very end of the cell, and moving it one character
                        ' before (because collapsing moves the range actually beyond the last character of the range)
                        Set rn = c.Range
                        rn.Collapse Direction:=wdCollapseEnd
                        rn.MoveEnd Unit:=wdCharacter, Count:=-1

                        ' somehow the last word of the contents of the cell is always Chr(13) & Chr(7)
                        ' and especially Chr(7) causes some very strange and murky problems
                        ' I end up avoiding them by not copying the last character, and by setting as a rule
                        ' that the contents of the first cell should always contain an empty line in the end
                        If c.Range.Words.Count <> ActiveDocument.Tables(1).Rows(1).Cells(1).Range.Words.Count Then
                            rn.FormattedText = w
                        Else
                            'MsgBox "The strange text is: " & w.Text
                            'the two byte values of this text (which obviously contains special characters with special
                            'meaning to Word can be found (and watched) with
                            'AscB(Mid(w.Text, 1, 1)) and  AscB(Mid(w.Text, 2, 1))
                            w.MoveEnd Unit:=WdUnits.wdCharacter, Count:=-1
                            rn.FormattedText = w
                        End If
                    Next w

                End If
                b = True
            End If

            i = i + 1
       Next c
   Next r

Вот изображения рассматриваемого документа Word. Первое изображение прежде выполняет макрос, второй между первым блоком кода и последним, в то время как третье изображение является получающимся документом.

Изображение 1 Изображение 2 Изображение 3

Именно.

4
ответ дан 17 December 2019 в 02:34
поделиться

Используйте текстовое свойство объекта Выбора поместить данные в строковую переменную, а не на буфер обмена:

Тусклый strTemp как Строка

strTemp = Выбор. Текст

Можно затем вставить текст, сохраненный в переменную в другом месте по мере необходимости.

-1
ответ дан 17 December 2019 в 02:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: