15. marts 2008 - 12:43Der er
31 kommentarer og 1 løsning
File handling
Jeg er begyndt på et program, som skal kunne tage en liste af "scrambled" ord som står sådan her:
ord1 ord2 ord3 ...
og "unscramble" dem (tjekker på en wordlist.txt, som har 1275 ord), sådan at de kommer i sådan en rækkefølge:
ord1,ord2,ord3,...
jeg er bare kommet lidt på bar bund, da jeg ikke kan finde ud af en måde at tjekke det på, sådan at jeg ikke skal vente i mere end 1 minut.. nogen som kan hjælpe med dette?
Her er min kode:
Option Explicit Const WORDLIST = "wordlist.txt"
Private Sub cmdUnscramble_Click() Dim i As Integer Dim strText(1275) As String
Open WORDLIST For Input As #1: ' Open WORDLIST for reading and name it #1
For i = 0 To 1274 Line Input #1, strText(i) Next i
' Her skal så koden ind, som tjekker og unscrambler
txtOutput.Text = Left(txtOutput.Text, (Len(txtOutput.Text) - 1)) ' To Remove Last "," Clipboard.SetText (txtOutput.Text) ' Copy to clipboard cmdUnscramble.Enabled = False MsgBox "Process complete. Text copied.", vbOKOnly, "Success!"
En bedre måde er nok at læse hele filen ind i en variabel på én gang, og splitte indholdet op efter linieskift (vbCrLf). Derved får du en array som du kan løbe igennem.
Jeg har erfaret at denne fremgangsmåde er mere effektiv i forhold til at læse 1 linie adgangen..
Nu er det noget tid siden jeg sidst har programmeret i VB, så jeg kan ikke huske om det er muligt.. og hvordan, hvis muligt..
Dim fso As New FileSystemObject ' opretter FileSystemObject for at kunne tilgå filsystemet Dim fso_readfile As TextStream ' opretter et TextStream objekt til læsning af filens indhold
Set fso_readfile = fso.OpenTextFile("wordlist.txt") ' Det kan være at du skal indsætte den FULDE sti indhold = fso_readfile.ReadAll ' læser alt indholdet og smider det over i variablen "indhold"
' frigør resourcerne: Set fso_readfile = Nothing ' set TextStream objektet til ingenting så objektet frigøres Set fso = Nothing ' set FileSystemObject objektet til ingenting så objektet frigøres
Dim strText strText = split(indhold, vbCrLf) ' splitter indholdet ved linieskift (vbCrLf) = opret array
ok, jeg har brugt 2 simple for loops til at skrive alle ordene ind i txtOutput.text, og det virker fint.. mit eneste problem nu, er at tjekke ordene og unscramble dem..
min idé var at tjekke hver bogstav på de scramblede ord, og se om de passede.. hvis alle bogstaverne er til stede i én linje i WORDLIST, vil jeg gå ud fra at det er det samme ord, og derfor sætte dét ord ind i txtOutput.Text, og så fortsætte.. men hvordan..? o.O eller er der en hurtigere måde?
på min liste af "scramblede" ord, kommer "1h1x83t", og et eller andet sted i WORDLIST ligger thx1138..
min idé var så at jeg så skulle tage 1h1x83t, og tjekke det, bogstav for bogstav (eller tal selvf.), og se om den bogstav (eller tal) er i et af ordene i WORDLIST.. sådan i thx1183 ville det finde det første 1-tal, og på en eller anden måde udelukke det, sådan at det ikke findes igen, og så søge videre, så at det finder h-et.. så når det har fundet alle bogstaverne i et ord, ville det blive tilføjet til txtOutput.Text.. er det forståeligt?
jeg vil bare vide om min idé kunne laves om til en lidt mindre indviklet en, siden den ser ud til at komme til at kræve rimeligt indviklet koding, store If nests og sådan noget forskelligt.. og hvis ikke, hvordan jeg får udelukket den bogstav, så den ikke bliver fundet igen, for det har jeg lidt problemer med.. :)
for at give lidt mere info, kan jeg give denne kode, som jeg har lavet indtil videre:
For intJ = 0 To 1274 For intK = 1 To Len(strText(intJ)) If (Mid(txtInput.Text, intK, 1) = Mid(strText(intJ), intK, 1)) Then txtOutput.Text = txtOutput.Text & Mid(strText(intJ), intK, 1) End If Next intK Next intJ
det jeg så har lavet her, er simpelthen for at se om det ville være lettere at forstå, siden jeg ikke kan finde hoved eller hale i noget af det jeg prøver at forklare.. er ikke så god til at forklare, så jeg skrev en lille kode, som måske demonstrerer lidt bedre.. den kode jeg har lavet er langt fra det endelige resultat jeg leder efter, men det er i den retning jeg vil hen.. jeg skal bare finde ud hvordan jeg laver følgende:
- et komma skal ind efter hvert ord der bliver fundet - men kun hvis der bliver fundet noget - teksten skal kun vises i txtOutput.Text hvis alle bogstaverne stemmer.. hvis ét tilfælde af if statementet ikke passer, skal det ikke med.. muligvis boolean? - de bogstaver der bliver fundet i strText(intJ), skal blive udelukket, sådan at de ikke kan findes igen
og så er der det, at indtil videre leder den kun efter bogstaverne i samme rækkefølge.. sådan at "thx1183" ville stemme med "thx1183", men ikke med "1h1x83t".. hvordan kan det laves om på en simpel måde?
Function IdenticalAtHeart(String1 As String, String2 As String) As Boolean IdenticalAtHeart = False If Len(String1) <> Len(String2) Then Exit Function If String1 = String2 Then IdenticalAtHeart = True Exit Function End If
'Sæt bogstaver til uppercase. Dim S1 As String: Dim S2 As String S1 = UCase(String1): S2 = UCase(String2)
Dim bByte As Byte Const FyldKarakter As String * 1 = "_"
For bByte = 1 To Len(S1) If InStr(S2, Mid(S1, bByte, 1)) > 0 Then 'Et tegn må kun kunne findes 1 gang. Mid(S2, InStr(S2, Mid(S1, bByte, 1)), 1) = FyldKarakter Else Exit Function 'Forskel - farvel. End If Next bByte IdenticalAtHeart = True End Function
Sub TestIfIdenticalAtHeart() Debug.Print "** Start **" Debug.Print "I expect True , and I get: ", IdenticalAtHeart("1h1x83t", "1h1x83t") Debug.Print "I expect False, and I get: ", IdenticalAtHeart("1h1x83t", "1h1x83") Debug.Print "I expect True , and I get: ", IdenticalAtHeart("1h1x83t", "t1h1x83") Debug.Print "I expect False, and I get: ", IdenticalAtHeart("1h1x83x", "1h1x83t") Debug.Print "I expect True , and I get: ", IdenticalAtHeart("1112111", "1111112") Debug.Print "I expect False, and I get: ", IdenticalAtHeart("1112112", "1111112")
Debug.Print "** Stop **" End Sub
Hvis det ikke er, så ignorer indlægget :-)
Hvis det er, så kan du overveje om du vil hvorfor de to strenge ikke var helt identiske, og så ellers passe det ind i den array-struktur du har valgt.
jeg sidder ikke ved min computer lige nu, så jeg får ikke testet det, men jeg vil lige spørge et par ting om den kode du gav mig:
- du deklarer en byte variabel.. hvad vil det sige? at den kun kan have 1 char? - hvad laver InStr() funktion, og hvorfor bruger du det i Mid() funktionen? - din const deklaration.. hvad vil "* 1" delen sige? - Const FyldKarakter As String * 1 = "_"
og så er der debug parten.. jeg har aldrig forstået Debug.Print rigtigt, hvordan man bruger det, og hvor det kan ses.. kan du give mig lidt hurtig basisk information om det? jeg vil bare gerne vide lidt om mine koder når jeg laver et program, så jeg altid kan se tilbage og vide hvad der sker, og kan lære lidt mere.. :-)
ellers ser det meste ud til at være lige det jeg har brug for.. vil bare lige forstå det lidt mere.. :-)
byte variabel - bruges til lille løkke (længden af strengen). Erklæret som Byte (som kan rumme værdier fra 0 til 255) da den tager mindst plads. Det er ikke 1 char, men derimod et heltal med begrænset pladsforbrug. Andre typer er også ok, men er "opdraget" med at 640k er nok til enhver :-)
InStr - VB funktion som kan fortælle på hvilken position en given delstreng befinder sig på inde i en anden streng. Har flere forskellige returværdier, men giver mere end 0 hvis delstrengen findes
Hvad den laver i Mid()? fortæller hvilken karakter der skal erstattes med en fyldkarakter - for at undgå at det samme tegn bliver valideret 2 gange.
Betydning af "Const FyldKarakter As String * 1 = "_" " Const = konstant, værdien må ikke ændre sig. Her brugt fordi du måske ønsker en værdi en understregning. Kunne også være anbragt i koden. Er ikke anbragt der fordi det er bedst at have den slags samlet 1 sted, hvis man nu lige vil ændre værdien, og den tilfældigvis er brugt 7 steder. Udover dovenskab, så sikrer det også at man altid får ændret alle steder. * 1 - lidt i stil med byte-erklæringen. Jeg fortæller bare at det er en streng med en max. længde på 1 jeg ønsker. (Indrømmet, lidt overflødig her :-))
Debug.Print - skriver i det lille debug vindue. Kan ikke håndtere alverden af fancy ting, men er ret behageligt når man bare lige skal teste returværdier for en funktion. Det svarer en smule til at man kunne skrive almindelige tekster på skærmen, fordelen er at du slipper for at forlade udviklingsmiljøet, og du slipper for at skulle rydde op i diverse forms hvor du ellers skulle have vist dine mellemregninger.
Hovedprincippet bag funktionen er så tidligt som muligt at få et negativt svar da det forventes at den skal kaldes ret mange gange i dit program. Strukturen i funktionen kan med sikkerhed laves på mindst 20 andre måder, og stadigvæk virke korrekt :-) (charmen ved at programmere er ofte at der som regel er mere end 1 måde at gøre tingene (rigtigt) på :-)
En måde at undersøge/lære på, er ved at indsætte f.eks. Debug.Print forskellige steder i koden, så du kan se udviklingen i de forskellige variable i løkker. Når udtryk bliver sammensat, som Mid() sætningen, så skil dem ad i en Debug.Print sætning, så du kan se hvad enkeltdelene gør. Derudover så er F1-hjælp altid en pragtfuld krykke :-)
Håber det kastede lidt lys over min uforklarede kode :-)
mangler bare lige at forstå hvad Mid(S2, InStr(S2, Mid(S1, bByte, 1)), 1) gør.. ville det ikke være nok at sige Mid(S2, bByte, 1) ? hvad resultat giver Mid(S2, InStr(S2, Mid(S1, bByte, 1)), 1) ?
smid bare forklaringen ind som et svar, så får du dine points.. tak for hjælpen.. :-)
ok, nu har jeg prøvet at slås med en kode, for at få det til at virke i rimelig lang tid, men jeg kan ikke få følgende til at virke:
For intJ = 0 To Len(txtInput.Text) If (Mid(txtInput.Text, intJ, 1) = Asc(13)) Or (Mid(txtInput.Text, intJ, 1) = Asc(10)) Then ' pkt. 1 strScrambled(1) = Mid(txtInput.Text, 1, intJ - 1) ' pkt. 2 Mid(txtInput.Text, 1, intJ) = "" ' pkt. 3 End If Next intJ
pkt. 1 : jeg vil finde ud af hvor en newline er, så det ikke kommer med i søgningen (der er 10 "scramblede" ord i en liste nedad, og alle skal tjekkes på en gang) pkt. 2 : dette er midlertidigt kun for at tjekke, jeg ved ikke hvordan jeg skal få ordene ind i en array der, siden array'en har 10 pladser og det er i et for loop, som kører på 0 To Len(txtInput.Text).. pkt. 3 : den siger at jeg ikke kan gøre dette, at jeg kræver en variabel.. jeg ved at denne kode slet ikke kan bruges, siden det ville springe en hel del ord over i længden, men aner ikke hvordan det kan gøres ellers?
dette ville være min idé, men jeg har åbenbart brug for mere hjælp her.. kan du hjælpe mig igennem dette program, så vil jeg med glæde smide nogle flere points ind.. det blev vist besværligere end jeg troede.. o.O
--- de 9 sidste ord er lidt forskudte, der er en tom linje mellem hvert ord og der er en tom linje til sidst også.. jeg kan ikke få mig selv til at tænke helt klart i dette projekt.. hvordan får jeg tjekket dem alle med IdenticalAtHeart() ? alle 10 ord skal (efter min idé) sættes ind i et array(10), men det kan gøres anderledes, hvis det er nemmere.. når ordene er sat ind i array'et, skulle jeg meget gerne have styr på resten.. :-)
jeg åbner med glæde et nyt spm på 170 point ekstra, hvis du kan hjælpe mig med dette.. på forhånd tak.. :-)
Har været på påskeferie :-), behageligt & fredeligt, helt uden pc'ere :-)
Mht. 19/03-2008 19:23:21 Skriv et par print.debug sætninger omkring området, trace (F8) dig igennem et par gange.
Mht. endeligt resultat. Jeg skal lige forstå præcist hvad du gerne vil. Du har 2 tekstfiler. Den ene indeholder en lang liste over ord, den anden liste skal sammenholdes mod den første, og hvis et ord (fra liste 2) findes i liste 1 (uanset "stavemåde") vil du gerne have en String du kan vise i en textbox Sådan ca. ?
jeg har kun en tekstfil - wordlist.txt - som indeholder en liste over ordene.. den samme tekstfil bruges på en html side, hvor ordene bliver taget tilfældigt ud af wordlist.txt og bliver sat i en tilfældig rækkefølge..
så kopierer jeg de scramblede ord, og sætter dem ind i txtInput (multiline), og skal derefter trykke på cmdUnscramble og få dem til at "unscramble" og bliver sat i txtOutput (single line) i flg. format: "ord1,ord2,ord3...ord10"
det jeg står og mangler, er at finde ud af hvordan jeg får lagt de ord der bliver kopieret i txtInput i en array, sådan så jeg nemmer kan få sammenlignet dem med din funktion.. jeg ved ikke helt hvordan jeg skal skelne ordene fra hinanden, fordi programmet læser jo selvfølgelig txtInput (multiline) som en string af tekst..
alt mellem de to "---" er hvad der bliver kopieret ind til txtInput.. det første ord begynder helt inde på linien, men de sidste ni ord har et mellemrum foran dem, og hver tom linie mellem ordene har et mellemrum på dem også..
Function IdenticalAtHeart(String1 As String, String2 As String) As Boolean IdenticalAtHeart = False If Len(String1) <> Len(String2) Then Exit Function If String1 = String2 Then IdenticalAtHeart = True Exit Function End If
'Sæt bogstaver til uppercase. Dim S1 As String: Dim S2 As String S1 = UCase(String1): S2 = UCase(String2)
Dim bByte As Byte Const FyldKarakter As String * 1 = "_"
For bByte = 1 To Len(S1) If InStr(S2, Mid(S1, bByte, 1)) > 0 Then 'Et tegn må kun kunne findes 1 gang. Mid(S2, InStr(S2, Mid(S1, bByte, 1)), 1) = FyldKarakter Else Exit Function 'Forskel - farvel. End If Next bByte IdenticalAtHeart = True End Function
Dim lX As Long Dim lY As Long Dim strAnswer As String strAnswer = "" For lX = 1 To UBound(InputArray) For lY = 1 To UBound(DiskListe) If IdenticalAtHeart(Trim(InputArray(lX)), Trim(DiskListe(lY))) Then strAnswer = strAnswer & DiskListe(lY) & "," 'strAnswer = strAnswer & Trim(InputArray(lX)) & "," Exit For End If Next lY Next lX If Len(strAnswer) > 1 Then strAnswer = Left(strAnswer, Len(strAnswer) - 1) End Sub
undskyld al misforståelsen, men det jeg står og mangler er at få alt i txtInput.Text at blive sat i en array men kun 10 ord, adskilt af mellemrum..
hvis ordene står sådan her: ooidge
rrmdue
apah1l
rvoayge
etresv
idbbigr
egrnlea
veyrha
ymomaa
osoetrc
vil jeg have de tomme linier væk, og alle linierne der indeholder ord, skal (automatisk, siden ordene er tilfældige, og ikke altid de samme) blive sat ind i et array (trimmed for mellemrum), der ville rumme 10 ord - kun de ord der er listet..
der fra kan jeg nok finde ud af resten, men mangler bare lige en funktion som kan finde ud af det.. :)
Nedenstående tager indholdet fra Textbox1 (ved Change event), bearbejder input (en lang streng med diverse ord, blanke linier og CarriageReturn/LineFeeds) til en array, som sammenlignes med en anden array. Resultatet vises i Textbox2 (opret den eller skift til noget andet) og er de ord der blev fundet.
Option Explicit Dim InputArray() Dim DiskListe() Dim OutPutArray()
Function IdenticalAtHeart(String1 As String, String2 As String) As Boolean IdenticalAtHeart = False If Len(String1) <> Len(String2) Then Exit Function If String1 = String2 Then IdenticalAtHeart = True Exit Function End If
'Sæt bogstaver til uppercase. Dim S1 As String: Dim S2 As String S1 = UCase(String1): S2 = UCase(String2)
Dim bByte As Byte Const FyldKarakter As String * 1 = "_"
For bByte = 1 To Len(S1) If InStr(S2, Mid(S1, bByte, 1)) > 0 Then 'Et tegn må kun kunne findes 1 gang. Mid(S2, InStr(S2, Mid(S1, bByte, 1)), 1) = FyldKarakter Else Exit Function 'Forskel - farvel. End If Next bByte IdenticalAtHeart = True End Function
Private Sub FraTextBox1TilArray() Dim arrSplit Dim lX As Long
arrSplit = Split(TextBox1.Text, vbCrLf)
ReDim InputArray(0) For lX = 1 To UBound(arrSplit) If Len(Trim(arrSplit(lX))) > 0 Then ReDim Preserve InputArray(UBound(InputArray) + 1) InputArray(UBound(InputArray)) = Trim(arrSplit(lX)) End If Next lX End Sub
Dim lX As Long Dim lY As Long Dim strAnswer As String ReDim OutPutArray(0)
For lX = 1 To UBound(InputArray) For lY = 1 To UBound(DiskListe) If IdenticalAtHeart(Trim(InputArray(lX)), Trim(DiskListe(lY))) Then strAnswer = strAnswer & DiskListe(lY) & "," 'strAnswer = strAnswer & Trim(InputArray(lX)) & "," Exit For End If Next lY Next lX TextBox2.Value = strAnswer End Sub
Private Sub TextBox1_Change() FraTextBox1TilArray Sammenlign End Sub
lige præcis! :) det var lige det jeg manglede.. nu kan jeg arbejde mig frem til resten.. mangler bare lige at tilføje alle ordene i wordlist til "DiskListe", men den klarer jeg :)
smid et svar og du får dine points.. åbner også andet spørgsmål med lidt ekstra points for den store indsats :)
hehe.. ja, tak for hjælpen.. prøver bare at slås med at få den første linie til at blive unscrambled også... opretter et nyt spørgsmål med flere points, siden det tog så lang tid, og du skulle hjælpe med mere end jeg havde regnet med.. :)
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.