2

根据 google 组,此宏可用于在 MS Office 中打印拼写错误的单词。

https://groups.google.com/g/microsoft.public.word.spelling.grammar/c/OiFYPkLAbeU

libre-office writer 中是否有类似的选项?

4

6 回答 6

1

以下子例程复制了 Google 组中的代码所做的事情。它比 MS 版本更冗长,但这是 LibreOffice / OpenOffice 所期望的。它只检查拼写检查行,而不检查绿色语法检查行,Google 组中的 MS 版本也是如此。

Sub UnderlineMisspelledWords

    ' From OOME Listing 315 Page 336
    GlobalScope.BasicLibraries.loadLibrary( "Tools" )
    Dim sLocale As String
    sLocale = GetRegistryKeyContent("org.openoffice.Setup/L10N", FALSE).getByName("ooLocale")

    ' ooLocale appears to return a string that consists of the language and country
    ' seperated by a dash, e.g. en-GB
    Dim nDash As Integer
    nDash = InStr(sLocale, "-")

    Dim aLocale As New com.sun.star.lang.Locale
    aLocale.Language = Left(sLocale, nDash - 1)
    aLocale.Country = Right(sLocale, Len(sLocale) -nDash )

    Dim oSpeller As Variant
    oSpeller = createUnoService("com.sun.star.linguistic2.SpellChecker")

    Dim emptyArgs() as new com.sun.star.beans.PropertyValue

    Dim oCursor As Object
    oCursor = ThisComponent.getText.createTextCursor()
    oCursor.gotoStart(False)
    oCursor.collapseToStart()

    Dim s as String, bTest As Boolean
    Do 
        oCursor.gotoEndOfWord(True)
        s = oCursor.getString()
        bTest = oSpeller.isValid(s, aLocale, emptyArgs())

        If Not bTest Then    
            With oCursor
                .CharUnderlineHasColor = True
                .CharUnderlineColor = RGB(255, 0,0)
                .CharUnderline = com.sun.star.awt.FontUnderline.WAVE
                ' Possible alternatives include SMALLWAVE, DOUBLEWAVE and BOLDWAVE
            End With
        End If    
    Loop While oCursor.gotoNextWord(False)

End Sub    

这会将字体的实际格式更改为带有红色波浪下划线,它将像任何其他格式一样打印出来。如果文档中的任何拼写错误的单词已经有某种下划线,那么它将丢失。

您可能希望在打印后删除下划线。以下 Sub 仅在其样式与第一个例程添加的行的样式完全匹配的情况下删除下划线。

Sub RemoveUnderlining

    Dim oCursor As Object
    oCursor = ThisComponent.getText.createTextCursor()
    oCursor.gotoStart(False)
    oCursor.collapseToStart()

    Dim s as String, bTest As Boolean
    Do 
    
        oCursor.gotoEndOfWord(True) 
        
        Dim bTest1 As Boolean        
        bTest1 = False
        If oCursor.CharUnderlineHasColor = True Then
            bTest1 = True
        End If
        
        Dim bTest2 As Boolean  
        bTest2 = False
        If oCursor.CharUnderlineColor = RGB(255, 0,0) Then
            bTest2 = True
        End If
        
        Dim bTest3 As Boolean  
        bTest3 = False
        If oCursor.CharUnderline = com.sun.star.awt.FontUnderline.WAVE Then
            bTest3 = True
        End If
        
        If bTest1 And bTest2 And bTest3 Then
            With oCursor
                .CharUnderlineHasColor = False
                .CharUnderline = com.sun.star.awt.FontUnderline.NONE
            End With
        End If
    Loop While oCursor.gotoNextWord(False)

End Sub

这不会恢复任何被红色波浪线替换的原始下划线。删除可以恢复这些波浪线的其他方法是:

  1. undo(Ctrl Z),但您需要为文档中的每个单词执行一次,这可能有点痛苦。

  2. 对文档的临时副本运行子例程UnderlineMisspelledWords,然后在打印后将其丢弃。

我希望这就是你要找的。

于 2021-06-17T14:35:14.990 回答
1

针对您的上述评论,修改上述子例程来做到这一点很简单,而不是绘制波浪线。下面的代码打开一个新的 Writer 文档,并在其中写入一个拼写错误的单词列表以及拼写检查器建议的替代词:

Sub ListMisSpelledWords

    ' From OOME Listing 315 Page 336
    GlobalScope.BasicLibraries.loadLibrary( "Tools" )
    Dim sLocale As String
    sLocale = GetRegistryKeyContent("org.openoffice.Setup/L10N", FALSE).getByName("ooLocale")

    ' ooLocale appears to return a string that consists of the language and country
    ' seperated by a dash, e.g. en-GB
    Dim nDash As Integer
    nDash = InStr(sLocale, "-")

    Dim aLocale As New com.sun.star.lang.Locale
    aLocale.Language = Left(sLocale, nDash - 1)
    aLocale.Country = Right(sLocale, Len(sLocale) -nDash )

    Dim oSource As Object 
    oSource = ThisComponent

    Dim oSourceCursor As Object
    oSourceCursor = oSource.getText.createTextCursor()
    oSourceCursor.gotoStart(False)
    oSourceCursor.collapseToStart()

    Dim oDestination As Object
    oDestination = StarDesktop.loadComponentFromURL( "private:factory/swriter",  "_blank", 0, Array() )

    Dim oDestinationText as Object
    oDestinationText = oDestination.getText()

    Dim oDestinationCursor As Object
    oDestinationCursor = oDestinationText.createTextCursor()

    Dim oSpeller As Object
    oSpeller = createUnoService("com.sun.star.linguistic2.SpellChecker")

    Dim oSpellAlternatives As Object, emptyArgs() as new com.sun.star.beans.PropertyValue
    Dim sMistake as String, oSpell As Object, sAlternatives() as String, bTest As Boolean, s As String, i as Integer

    Do

        oSourceCursor.gotoEndOfWord(True)
        sMistake = oSourceCursor.getString()

        bTest = oSpeller.isValid(sMistake, aLocale, emptyArgs())

        If Not bTest Then
            oSpell = oSpeller.spell(sMistake, aLocale, emptyArgs())
            sAlternatives = oSpell.getAlternatives()
            s = ""
            for i = LBound(sAlternatives) To Ubound(sAlternatives) - 1
                s = s & sAlternatives(i) & ", "
            Next i
            s = s & sAlternatives(Ubound(sAlternatives))
            oDestinationText.insertString(oDestinationCursor, sMistake & ":  " & s & Chr(13), False)
        End If    

    Loop While oSourceCursor.gotoNextWord(False)

End Sub
于 2021-06-23T19:34:33.547 回答
1

我不知道字典,但是,在回答您之前的评论时,如果您在下方Loop While和上方粘贴以下代码,End Sub它将导致新打开的 Writer 文档中的文本被排序而没有重复。它不是很优雅,但它适用于我尝试过的文本。

oDestinationCursor.gotoStart(False)
oDestinationCursor.gotoEnd(True)

Dim oSortDescriptor As Object
oSortDescriptor = oDestinationCursor.createSortDescriptor()
oDestinationCursor.sort(oSortDescriptor)

Dim sParagraphToBeChecked As String
Dim sThisWord As String
sThisWord = ""
Dim sPreviousWord As String
sPreviousWord = ""

oDestinationCursor.gotoStart(False)
oDestinationCursor.collapseToStart()

Dim k As Integer
Do
    oDestinationCursor.gotoEndOfParagraph(True)
    sParagraphToBeChecked = oDestinationCursor.getString()
    k = InStr(sParagraphToBeChecked, ":")
    If k <> 0 Then
        sThisWord = Left(sParagraphToBeChecked, k-1)
    End If
    If StrComp(sThisWord, sPreviousWord, 0) = 0 Then
        oDestinationCursor.setString("")
    End If
    sPreviousWord = sThisWord
Loop While oDestinationCursor.gotoNextParagraph(False)

Dim oReplaceDescriptor As Object
oReplaceDescriptor =  oDestination.createReplaceDescriptor()
oReplaceDescriptor.setPropertyValue("SearchRegularExpression", TRUE)
oReplaceDescriptor.setSearchString("^$")
oReplaceDescriptor.setReplaceString("")
oDestination.replaceAll(oReplaceDescriptor)
于 2021-06-30T15:32:13.557 回答
1

似乎我没有发现这一点,因为我测试它的文本只包含正确的或有多个替代项的单词。我设法通过输入一个由拼写检查器无法提出任何替代方案的随机字符组成的单词来复制错误。如果没有找到替代方案,该函数.getAlternatives()将返回一个大小为 -1 的数组,因此可以通过在使用数组之前测试此条件来避免错误。下面是Do添加了这样一个条件的子程序中第一个循环的修改版本。如果你用它替换现有的循环,它应该消除错误。

Do

    oSourceCursor.gotoEndOfWord(True)
    sMistake = oSourceCursor.getString()

    bTest = oSpeller.isValid(sMistake, aLocale, emptyArgs())

    If Not bTest Then
        oSpell = oSpeller.spell(sMistake, aLocale, emptyArgs())
        sAlternatives = oSpell.getAlternatives()
        s = ""
        If Ubound(sAlternatives) >= 0 Then
            for i = LBound(sAlternatives) To Ubound(sAlternatives) - 1
                s = s & sAlternatives(i) & ", "
            Next i
            s = s & sAlternatives(Ubound(sAlternatives))
        End If            
        oDestinationText.insertString(oDestinationCursor, sMistake & ":  " & s & Chr(13), False)
    End If    

Loop While oSourceCursor.gotoNextWord(False)

在重新阅读整个子例程时,我认为如果将变量sMistake重命名为类似的东西会提高其可读性sWordToBeChecked,因为该变量包含的字符串并不总是拼写错误。这当然需要在例程中的任何地方进行更改,而不仅仅是在上面的代码段中。

于 2021-07-02T09:29:06.520 回答
1

下面是一个修改后的版本,它使用了 Jim K 在他的回答中建议的调度程序go to end of word is not always follow。我已经完整地写出来了,因为更改比添加或替换块更广泛。特别是,必须在创建空目标文档之前获取视图光标,否则例程将对其进行拼写检查。

Sub ListMisSpelledWords2

    ' From OOME Listing 315 Page 336
    GlobalScope.BasicLibraries.loadLibrary( "Tools" )
    Dim sLocale As String
    sLocale = GetRegistryKeyContent("org.openoffice.Setup/L10N", FALSE).getByName("ooLocale")

    ' ooLocale appears to return a string that consists of the language and country
    ' seperated by a dash, e.g. en-GB
    Dim nDash As Integer
    nDash = InStr(sLocale, "-")

    Dim aLocale As New com.sun.star.lang.Locale
    aLocale.Language = Left(sLocale, nDash - 1)
    aLocale.Country = Right(sLocale, Len(sLocale) -nDash )

    Dim oSourceDocument As Object 
    oSourceDocument = ThisComponent

    Dim nWordCount as Integer
    nWordCount = oSourceDocument.WordCount    

    Dim oFrame  As Object, oViewCursor As Object
    With oSourceDocument.getCurrentController
        oFrame = .getFrame()
        oViewCursor = .getViewCursor()
    End With

    Dim oDispatcher as Object
    oDispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
    oDispatcher.executeDispatch(oFrame, ".uno:GoToStartOfDoc", "", 0, Array()) 

    Dim oDestinationDocument As Object
    oDestinationDocument = StarDesktop.loadComponentFromURL( "private:factory/swriter",  "_blank", 0, Array() )

    Dim oDestinationText as Object
    oDestinationText = oDestinationDocument.getText()

    Dim oDestinationCursor As Object
    oDestinationCursor = oDestinationText.createTextCursor()

    Dim oSpeller As Object
    oSpeller = createUnoService("com.sun.star.linguistic2.SpellChecker")

    Dim oSpellAlternatives As Object, emptyArgs() as new com.sun.star.beans.PropertyValue
    Dim sMistake as String, oSpell As Object, sAlternatives() as String, bTest As Boolean, s As String, i as Integer

    For i = 0 To nWordCount - 1

        oDispatcher.executeDispatch(oFrame, ".uno:WordRightSel", "", 0, Array())
        sWordToBeChecked = RTrim( oViewCursor.String )

        bTest = oSpeller.isValid(sWordToBeChecked, aLocale, emptyArgs())

        If Not bTest Then
            oSpell = oSpeller.spell(sWordToBeChecked, aLocale, emptyArgs())
            sAlternatives = oSpell.getAlternatives()
            s = ""
            If Ubound(sAlternatives) >= 0 Then
                for i = LBound(sAlternatives) To Ubound(sAlternatives) - 1
                    s = s & sAlternatives(i) & ", "
                Next i
                s = s & sAlternatives(Ubound(sAlternatives))
            End If            
            oDestinationText.insertString(oDestinationCursor, sWordToBeChecked & ":  " & s & Chr(13), False)
        End If

        oDispatcher.executeDispatch(oFrame, ".uno:GoToPrevWord", "", 0, Array())
        oDispatcher.executeDispatch(oFrame, ".uno:GoToNextWord", "", 0, Array())

    Next i

    oDestinationCursor.gotoStart(False)
    oDestinationCursor.gotoEnd(True)

    ' Sort the paragraphs
    Dim oSortDescriptor As Object
    oSortDescriptor = oDestinationCursor.createSortDescriptor()
    oDestinationCursor.sort(oSortDescriptor)

    ' Remove duplicates
    Dim sParagraphToBeChecked As String, sThisWord As String, sPreviousWord As String
    sThisWord = ""
    sPreviousWord = ""

    oDestinationCursor.gotoStart(False)
    oDestinationCursor.collapseToStart()

    Dim k As Integer
    Do
        oDestinationCursor.gotoEndOfParagraph(True)
        sParagraphToBeChecked = oDestinationCursor.getString()
        k = InStr(sParagraphToBeChecked, ":")
        If k <> 0 Then
            sThisWord = Left(sParagraphToBeChecked, k-1)
        End If
        If StrComp(sThisWord, sPreviousWord, 0) = 0 Then
            oDestinationCursor.setString("")
        End If
        sPreviousWord = sThisWord
    Loop While oDestinationCursor.gotoNextParagraph(False)

    ' Remove empty paragraphs
    Dim oReplaceDescriptor As Object
    oReplaceDescriptor =  oDestinationDocument.createReplaceDescriptor()
    oReplaceDescriptor.setPropertyValue("SearchRegularExpression", TRUE)
    oReplaceDescriptor.setSearchString("^$")
    oReplaceDescriptor.setReplaceString("")
    oDestinationDocument.replaceAll(oReplaceDescriptor)

End Sub
于 2021-07-04T20:38:06.443 回答
0

首先,针对您关于该错误的问题,我不是维护者,因此无法修复。但是,由于该错误涉及将文本光标移动到单词的开头和结尾,因此应该可以通过搜索单词之间的空白来绕过它。由于所有语言中的空白字符(我认为)都是相同的,因此从某些字母中识别某些字符的任何问题都无关紧要。最简单的方法是首先将文档的整个文本读入一个字符串,但 LibreOffice 字符串的最大长度为 2^16 = 65536 个字符,虽然这看起来很多,但它很容易太小而无法合理大小的文件。通过一次浏览一段文本可以避免该限制。根据 Andrew Pitonyak(OOME 第 388 页):“

下面的代码是对先前答案中子例程的另一种修改。这次它从段落中获取一个字符串,并通过查找单词之间的空格将其拆分为单词。然后它像以前一样对单词进行拼写检查。该子例程依赖于它下面列出的一些其他函数。这些允许您指定将哪些字符指定为单词分隔符(即空格)以及在单词的开头或结尾找到哪些字符时要忽略它们。这是必要的,例如,引用单词周围的引号不计为单词的一部分,即使引号内的单词拼写正确,这也会导致它被识别为拼写错误。

我不熟悉非拉丁字母,也没有安装合适的字典,但我粘贴了你的问题中的单词 go to end of word is not always follow ,即 testी、भारत 和 इंडिया 并且它们都未修改输出文档。

在查找同义词的问题上,由于每个拼写错误的单词都有多个建议,并且每个建议都有多个同义词,因此输出可能会迅速变得非常庞大和混乱。如果您的用户想使用不同的词,最好单独查找它们。

Sub ListMisSpelledWords3

    ' From OOME Listing 315 Page 336
    GlobalScope.BasicLibraries.loadLibrary( "Tools" )
    Dim sLocale As String
    sLocale = GetRegistryKeyContent("org.openoffice.Setup/L10N", FALSE).getByName("ooLocale")

    ' ooLocale appears to return a string that consists of the language and country
    ' seperated by a dash, e.g. en-GB
    Dim nDash As Integer
    nDash = InStr(sLocale, "-")

    Dim aLocale As New com.sun.star.lang.Locale
    aLocale.Language = Left( sLocale, nDash - 1)
    aLocale.Country = Right( sLocale, Len(sLocale) - nDash )

    Dim oSource As Object 
    oSource = ThisComponent

    Dim oSourceCursor As Object
    oSourceCursor = oSource.getText.createTextCursor()
    oSourceCursor.gotoStart(False)
    oSourceCursor.collapseToStart()

    Dim oDestination As Object
    oDestination = StarDesktop.loadComponentFromURL( "private:factory/swriter",  "_blank", 0, Array() )

    Dim oDestinationText as Object
    oDestinationText = oDestination.getText()

    Dim oDestinationCursor As Object
    oDestinationCursor = oDestinationText.createTextCursor()

    Dim oSpeller As Object
    oSpeller = createUnoService("com.sun.star.linguistic2.SpellChecker")

    Dim oSpellAlternatives As Object, emptyArgs() as new com.sun.star.beans.PropertyValue
    Dim sWordToCheck as String, oSpell As Object, sAlternatives() as String, bTest As Boolean
    Dim s As String, i as Integer, j As Integer, sParagraph As String, nWordStart As Integer, nWordEnd As Integer
    Dim nChar As Integer

    Do

        oSourceCursor.gotoEndOfParagraph(True)

        sParagraph = oSourceCursor.getString() & " " 'It is necessary to add a space to the end of
        'the string otherwise the last word of the paragraph is not recognised.

        nWordStart = 1
        nWordEnd = 1

        For i = 1 to Len(sParagraph)

            nChar = ASC(Mid(sParagraph, i, 1))

            If IsWordSeparator(nChar) Then   '1

                If nWordEnd > nWordStart Then   '2

                sWordToCheck = TrimWord( Mid(sParagraph, nWordStart, nWordEnd - nWordStart) )

                    bTest = oSpeller.isValid(sWordToCheck, aLocale, emptyArgs())

                    If Not bTest Then   '3
                        oSpell = oSpeller.spell(sWordToCheck, aLocale, emptyArgs())
                        sAlternatives = oSpell.getAlternatives()
                        s = ""                        
                        If Ubound(sAlternatives) >= 0 Then   '4
                            for j = LBound(sAlternatives) To Ubound(sAlternatives) - 1
                                s = s & sAlternatives(j) & ", "
                            Next j
                                s = s & sAlternatives(Ubound(sAlternatives))
                        End If          '4 
                        oDestinationText.insertString(oDestinationCursor, sWordToCheck & " :  " & s & Chr(13), False)
                    End If  '3

                End If   '2
                    nWordEnd = nWordEnd + 1
                    nWordStart = nWordEnd
                Else
                    nWordEnd = nWordEnd + 1
            End If    '1

        Next i

    Loop While oSourceCursor.gotoNextParagraph(False)

    oDestinationCursor.gotoStart(False)
    oDestinationCursor.gotoEnd(True)

    Dim oSortDescriptor As Object
    oSortDescriptor = oDestinationCursor.createSortDescriptor()
    oDestinationCursor.sort(oSortDescriptor)

    Dim sParagraphToBeChecked As String
    Dim sThisWord As String
    sThisWord = ""
    Dim sPreviousWord As String
    sPreviousWord = ""

    oDestinationCursor.gotoStart(False)
    oDestinationCursor.collapseToStart()

    Dim k As Integer
    Do
        oDestinationCursor.gotoEndOfParagraph(True)
        sParagraphToBeChecked = oDestinationCursor.getString()
        k = InStr(sParagraphToBeChecked, ":")
        If k <> 0 Then
            sThisWord = Left(sParagraphToBeChecked, k-1)
        End If
            If StrComp(sThisWord, sPreviousWord, 0) = 0 Then
            oDestinationCursor.setString("")
        End If
        sPreviousWord = sThisWord
    Loop While oDestinationCursor.gotoNextParagraph(False)

    Dim oReplaceDescriptor As Object
    oReplaceDescriptor =  oDestination.createReplaceDescriptor()
    oReplaceDescriptor.setPropertyValue("SearchRegularExpression", TRUE)
    oReplaceDescriptor.setSearchString("^$")
    oReplaceDescriptor.setReplaceString("")
    oDestination.replaceAll(oReplaceDescriptor)

End Sub

'----------------------------------------------------------------------------

' From OOME Listing 360. 
Function IsWordSeparator(iChar As Integer) As Boolean

    ' Horizontal tab \t 9
    ' New line \n 10
    ' Carriage return \r 13
    ' Space   32
    ' Non-breaking space   160     

    Select Case iChar
    Case 9, 10, 13, 32, 160
        IsWordSeparator = True
    Case Else
        IsWordSeparator = False
    End Select    
End Function

'-------------------------------------

' Characters to be trimmed off beginning of word before spell checking
Function IsPermissiblePrefix(iChar As Integer) As Boolean

    ' Symmetric double quote " 34
    ' Left parenthesis ( 40
    ' Left square bracket [ 91
    ' Back-tick ` 96
    ' Left curly bracket { 123
    ' Left double angle quotation marks « 171
    ' Left single quotation mark ‘ 8216
    ' Left single reversed 9 quotation mark ‛ 8219
    ' Left double quotation mark “ 8220
    ' Left double reversed 9 quotation mark ‟ 8223

    Select Case iChar
    Case 34, 40, 91, 96, 123, 171, 8216, 8219, 8220, 8223
        IsPermissiblePrefix = True
    Case Else
        IsPermissiblePrefix = False
    End Select 

End Function

'-------------------------------------

' Characters to be trimmed off end of word before spell checking
Function IsPermissibleSuffix(iChar As Integer) As Boolean

    ' Exclamation mark ! 33
    ' Symmetric double quote " 34
    ' Apostrophe ' 39
    ' Right parenthesis ) 41
    ' Comma , 44
    ' Full stop . 46
    ' Colon : 58
    ' Semicolon ; 59
    ' Question mark ? 63
    ' Right square bracket ] 93
    ' Right curly bracket } 125
    ' Right double angle quotation marks » 187
    ' Right single quotation mark ‘ 8217
    ' Right double quotation mark “ 8221

    Select Case iChar
    Case 33, 34, 39, 41, 44, 46, 58, 59, 63, 93, 125, 187, 8217, 8221
        IsPermissibleSuffix = True
    Case Else
        IsPermissibleSuffix = False
    End Select    

End Function

'-------------------------------------

Function TrimWord( sWord As String) As String

    Dim n as Integer
    n = Len(sWord)
    
    If n > 0 Then
    
        Dim m as Integer :  m = 1
        Do While IsPermissiblePrefix( ASC(Mid(sWord, m, 1) ) ) And m <= n
                m = m + 1
        Loop
    
        Do While IsPermissibleSuffix( ASC(Mid(sWord, n, 1) ) ) And n >= 1
                n = n - 1
        Loop
        
        If n > m Then
            TrimWord = Mid(sWord, m, (n + 1) - m)
        Else
            TrimWord = sWord
        End If
            
    Else
        TrimWord = ""
    End If

End Function
于 2021-07-06T19:54:05.537 回答