Avatar billede i-mox Nybegynder
11. maj 2012 - 10:13 Der er 15 kommentarer og
1 løsning

Finde og opmarkere forskelle mellem to tekststrenge

Jeg skal finde og opmarkere forskelle mellem to tekststrenge, som jeg har gemt i en Access Database.

Jeg har ledt på nettet efter en algoritme, som jeg kunne sakse, men de implementationer, jeg har fundet, er i C# (som jeg ikke kan få til at virke på min WebMatrix-installation) eller Python, som jeg ikke kan skrive.

Det er noget tid siden, jeg har programmeret, og jeg er absolut stærkest i VBScript, men er begyndt at lege lidt med VB.Net nu, så jeg kan ikke bare lige skrive en algoritme selv, og jeg har ærlig talt svært ved at forstå, hvordan jeg skal implementere de algoritmer, jeg har fundet.

http://www.mathertel.de/Diff/DiffDoku.aspx

Denne her f.eks. kan jeg slet ikke få til at køre, selvom den virker præcis som det, jeg skal bruge. Når jeg prøver at køre filer derfra får jeg en parserfejl, når den når til noget, der hedder runat-server - hvad jo nok ikke er skide godt.

Er der nogen, der ligger inde med en lille stump kode i VB Script eller noget .NET, som kan finde forskelle på to tekststrenge? Eller som evt. kan hjælpe med at implementere ovenstående, så det kører på min WebMatrix?
Avatar billede mireigi Novice
11. maj 2012 - 19:31 #1
Jeg har flikket den her sammen i VBScript.

Den er beregnet til websites, men du kan nok godt tilpasse den til andre behov. I det mindste kan det give dig en fornemmelse af, hvordan man gør det.

Det meste af koden skulle gerne være selvforklarende. Du har jo trods alt erfaring med VBScript.

arrResult = CompareStrings("Dette er en tekst", "Dette en tekst er", True)
If arrResult(0) Then strColor = "#FA0" Else strColor = "#F00"

For i = 0 To UBound(arrResult(2))
    If arrResult(0) Then strText = Mid(arrResult(1), i + 1, 1) Else strText = arrResult(1)(i)
    blnDifferent = arrResult(2)(i)

    If blnDifferent Then strText = "<span style=""color:" & strColor & ";"">" & strText & "</span>"
    If i > 0 AND NOT arrResult(0) Then strText = " " & strText

    Response.Write(strText)
Next
Response.Write("<br />")
For i = 0 To UBound(arrResult(4))
    If arrResult(0) Then strText = Mid(arrResult(3), i + 1, 1) Else strText = arrResult(3)(i)
    blnDifferent = arrResult(4)(i)

    If blnDifferent Then strText = "<span style=""color:" & strColor & ";"">" & strText & "</span>"
    If i > 0 AND NOT arrResult(0) Then strText = " " & strText

    Response.Write(strText)
Next

Function CompareStrings(strText, strCompareTo, blnCompareByChar)
    If NOT blnCompareByChar Then
        'Word comparison
        arrTextWords = Split(strText, " ")
        arrCompareToWords = Split(strCompareTo, " ")

        ReDim arrTextWordDiff(UBound(arrTextWords))
        ReDim arrCompareToWordDiff(UBound(arrCompareToWords ))

        If UBound(arrTextWords) > UBound(arrCompareToWords) Then
            intIndex = 0
            Do While intIndex <= UBound(arrCompareToWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= UBound(arrTextWords)
                arrTextWordDiff(intIndex) = False

                intIndex = intIndex + 1
            Loop
        ElseIf UBound(arrTextWords) < UBound(arrCompareToWords) Then
            intIndex = 0
            Do While intIndex <= UBound(arrTextWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= UBound(arrCompareToWords)
                arrCompareToWords(intIndex) = False

                intIndex = intIndex + 1
            Loop
        Else
            intIndex = 0
            Do While intIndex <= UBound(arrTextWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop
        End If

        CompareStrings = Array(blnCompareByChar, arrTextWords, arrTextWordDiff, arrCompareToWords, arrCompareToWordDiff)
    Else
        'Char comparison
        ReDim arrTextCharDiff(Len(strText))
        ReDim arrCompareToCharDiff(Len(strCompareTo))

        If Len(strText) > Len(strCompareTo) Then
            intIndex = 1
            Do While intIndex <= Len(strCompareTo)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= Len(strText)
                arrTextCharDiff(intIndex) = False

                intIndex = intIndex + 1
            Loop
        ElseIf Len(strText) < Len(strCompareTo) Then
            intIndex = 1
            Do While intIndex <= Len(strText)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= Len(strCompareTo)
                arrCompareToCharDiff(intIndex) = False

                intIndex = intIndex + 1
            Loop

        Else
            intIndex = 1
            Do While intIndex <= Len(strCompareTo)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop
        End If

        CompareStrings = Array(blnCompareByChar, strText, arrTextCharDiff, strCompareTo, arrCompareToCharDiff)
    End If
End Function
Avatar billede mireigi Novice
11. maj 2012 - 19:34 #2
Og selvfølgelig lige en lille rettelse :)

Nu viser den også korrekt angivelse af ord/tegn der ikke findes i begge ord.

arrResult = CompareStrings("Dette er en tekst", "Dette en tekst er", False)
If arrResult(0) Then strColor = "#FA0" Else strColor = "#F00"

For i = 0 To UBound(arrResult(2))
    If arrResult(0) Then strText = Mid(arrResult(1), i + 1, 1) Else strText = arrResult(1)(i)
    blnDifferent = arrResult(2)(i)

    If blnDifferent Then strText = "<span style=""color:" & strColor & ";"">" & strText & "</span>"
    If i > 0 AND NOT arrResult(0) Then strText = " " & strText

    Response.Write(strText)
Next
Response.Write("<br />")
For i = 0 To UBound(arrResult(4))
    If arrResult(0) Then strText = Mid(arrResult(3), i + 1, 1) Else strText = arrResult(3)(i)
    blnDifferent = arrResult(4)(i)

    If blnDifferent Then strText = "<span style=""color:" & strColor & ";"">" & strText & "</span>"
    If i > 0 AND NOT arrResult(0) Then strText = " " & strText

    Response.Write(strText)
Next

Function CompareStrings(strText, strCompareTo, blnCompareByChar)
    If NOT blnCompareByChar Then
        'Word comparison
        arrTextWords = Split(strText, " ")
        arrCompareToWords = Split(strCompareTo, " ")

        ReDim arrTextWordDiff(UBound(arrTextWords))
        ReDim arrCompareToWordDiff(UBound(arrCompareToWords ))

        If UBound(arrTextWords) > UBound(arrCompareToWords) Then
            intIndex = 0
            Do While intIndex <= UBound(arrCompareToWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= UBound(arrTextWords)
                arrTextWordDiff(intIndex) = True

                intIndex = intIndex + 1
            Loop
        ElseIf UBound(arrTextWords) < UBound(arrCompareToWords) Then
            intIndex = 0
            Do While intIndex <= UBound(arrTextWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= UBound(arrCompareToWords)
                arrCompareToWordDiff(intIndex) = True

                intIndex = intIndex + 1
            Loop
        Else
            intIndex = 0
            Do While intIndex <= UBound(arrTextWords)
                blnResult = arrCompareToWords(intIndex) <> arrTextWords(intIndex)

                arrTextWordDiff(intIndex) = blnResult
                arrCompareToWordDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop
        End If

        CompareStrings = Array(blnCompareByChar, arrTextWords, arrTextWordDiff, arrCompareToWords, arrCompareToWordDiff)
    Else
        'Char comparison
        ReDim arrTextCharDiff(Len(strText))
        ReDim arrCompareToCharDiff(Len(strCompareTo))

        If Len(strText) > Len(strCompareTo) Then
            intIndex = 1
            Do While intIndex <= Len(strCompareTo)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= Len(strText)
                arrTextCharDiff(intIndex) = True

                intIndex = intIndex + 1
            Loop
        ElseIf Len(strText) < Len(strCompareTo) Then
            intIndex = 1
            Do While intIndex <= Len(strText)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop

            Do While intIndex <= Len(strCompareTo)
                arrCompareToCharDiff(intIndex) = True

                intIndex = intIndex + 1
            Loop

        Else
            intIndex = 1
            Do While intIndex <= Len(strCompareTo)
                blnResult = Mid(strCompareTo, intIndex, 1) <> Mid(strText, intIndex, 1)

                arrTextCharDiff(intIndex) = blnResult
                arrCompareToCharDiff(intIndex) = blnResult

                intIndex = intIndex + 1
            Loop
        End If

        CompareStrings = Array(blnCompareByChar, strText, arrTextCharDiff, strCompareTo, arrCompareToCharDiff)
    End If
End Function
Avatar billede arne_v Ekspert
12. maj 2012 - 03:26 #3
C# kan konverteres til VB.NET automatisk med rimeligt gode resultater.
Avatar billede arne_v Ekspert
12. maj 2012 - 03:30 #4
Hvis strengene skal vaere lige lange og der skal sammenlignes position x i den ene med position x i den anden saa er det trivielt.

En generel sammenligning kraever en mere praecis definition af reglerne for output.

Hvad skal ABC sammenlignet med AXXXC give?

1)

slet B
inssaet XXX

2)

erstat BC med XXXC

3)

erstat B med X
indsaet XXC
Avatar billede i-mox Nybegynder
12. maj 2012 - 11:10 #5
Kære mireigi,

Tak for kode! Den virker som sådan. Men arne_v har fat i noget, som måske er essentielt, og som jeg glemte at nævne.

For koden virker perfekt til at sammenligne og opmarkere forskelle lige indtil der opstår en forskel.

DETTE ER TEKST 1 OG ALT HVAD DER...
DETTE ER TEKST 2 MEN ALT HVAD DER...

Den eneste forskel på disse to tekst (reelt) er, at der står OG i 1 og MEN i 2. Men i den kode, som du har skrevet opmarkeres alt efter 1/2 med rødt.

Det som jeg har behov for er noget, der virker som dette f.eks. www.text-compare.com.

Jeg er slet ikke skarp nok i VB Script til at kunne modificere din kode, men kan det led lade sig gøre?
Avatar billede mireigi Novice
12. maj 2012 - 12:07 #6
Hvis du skifter den sidste parameter til False i stedet for True, får du vist forskellene per ord:

CompareStrings("Dette er en tekst", "Dette en er tekst", False)

False = Find forskelle mellem ord på samme placering
True = Find forskelle mellem bogstaver på samme placering
Avatar billede i-mox Nybegynder
12. maj 2012 - 12:21 #7
Det prøvede jeg faktisk inden jeg skrev :-) Men så opfører den sig helt skørt.

Men der må være en fejl et eller andet sted, som jeg ikke kan finde. Det virker NÆSTEN 100% perfekt (på ord) og det er også det det skal. Men lige for at illustrere hvad problemet er:

DETTE ER ENS. HER ER FORSKELLEN. DETTE ER ENS.
DETTE ER ENS. DETTE ER FORSKELLEN. DETTE ER ENS.

I ovenstående eksempel er forskell HER/DETTE (kun et ord) og det opmarkeres fint.

Men nedenstående opmarkeres forkert, når jeg indsætter det ekstra ord "her", og der altså er 2 ords forskel.

DETTE ER ENS. HER ER FORSKELLEN. DETTE ER ENS.
DETTE ER ENS. DETTE HER ER FORSKELLEN. DETTE ER ENS.

Findes der nogen let måde at ændre det på?
Avatar billede i-mox Nybegynder
12. maj 2012 - 15:11 #8
Nå ja, pointen er selvfølgelig, at den i det sidste eksempel kun burde opmakrere "DETTE HER" og "HER ER", men den opmarkerer fra "ENS." og fremefter. Dette gælder som sagt kun, hvis der er to ords forskel, så algoritmen kører fint så længe der kun er et ord.
Avatar billede mireigi Novice
12. maj 2012 - 16:56 #9
Det er fordi den sammenligner på placeringen af hvert ord. Så den gør det egentlig rigtigt nok.

Jeg prøver at se, om jeg kan finde den løsning du søger, hvor den kun markerer ord, der ikke findes i begge tekster.
Avatar billede i-mox Nybegynder
12. maj 2012 - 20:03 #10
Det kunne simpelthen være super-fedt, hvis du kan finde en løsning. Jeg er, må jeg desværre indrømme, sgu nok ikke dygtig nok til det.

Jeg vil i virkeligheden gerne have et værktøj, der gør præcis det, som text-compare.com gør. Det er virkelig elegant (på char-niveau dog). Har siddet og prøvet at rode med din kode, men... lad os bare sige, at det jeg prøvede ikke virkede.
Avatar billede mireigi Novice
14. maj 2012 - 00:46 #11
Jeg må desværre kaste håndklædet i ringen :(

Opgaven er ganske enkelt for stor til at jeg kan klare den.

En fyldestgørende sammenligning, som den på text-compare.com, skal gøre følgende:

Findes et ord i kildeteksten på samme position i den anden tekst?
  Hvis "ja":
      Angiv ordet som fundet;
      Next;
  Hvis "nej":
      Findes ordet senere, uden at springe andre ord i kildeteksten over, eller passere fundne?
        Hvis "ja":
            Angiv ordet som fundet;
            Next;
        Hvis "nej":
            Findes dele af ordet, i rækkefølge, i ordet på samme plads i den anden tekst, i rækkefølge?
              Hvis "ja":
                  Marker de fundne dele;
                  Marker dele der ikke findes;
                  Marker de fundne dele i den anden tekst;
                  Marker dele i den anden tekst der ikke findes i kildeteksten;
                  Next;
              Hvis "nej":
                  Marker ordet som ikke fundet;
                  Next;
Findes der et ord i den anden tekst, som ikke findes i kildeteksten?
  Hvis "ja":
      Angiv ordet som ugyldigt;
      Next;



Dette er for indviklet at kode til at jeg kan overskue det.

Måske du kan få en anden til at hjælpe med det.

Ellers må du på Google og finde et open source library du kan downloade og enten tilføje til dit program eller installere på maskinen, så det kan kaldes via noget kode.

Beklager at jeg ikke kan hjælpe dig videre.
Avatar billede mireigi Novice
14. maj 2012 - 00:51 #12
Alternativt kan du kontakte text-compare.com, forklare dem situationen og spørge om du kan få udleveret kildekoden til deres sammenligning.
Avatar billede i-mox Nybegynder
14. maj 2012 - 09:25 #13
Kære Mireigi,

TUSIND tak for din indsats! Jeg er bare overvældet over, at du ville prøve. Jeg vil tage kontakt til text-compare og høre, om de vil åbne for godteposen.

Er du ikke god at smide et svar, så du kan få point? For reelt gør den kode, du har skrevet, jo præcis det, der står i spørgsmålet.
Avatar billede mireigi Novice
14. maj 2012 - 11:21 #14
Jo, det kan jeg da godt. Og tak for point :)

Håber du finder en løsning.
Avatar billede mireigi Novice
14. maj 2012 - 11:22 #15
Hov, skal lige huske at "Svare" også :)
Avatar billede i-mox Nybegynder
27. maj 2012 - 12:34 #16
Endte med at bruge textdiff til php - så jeg fandt desværre ingen løsning i vbscript, men nu kører det nogenlunde på denne måde.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester