Millaisellaohan ohjelma pätkällä pystyisi vb.net'lla saamaan aikaiseksi että leikkaus pöydältä ottaa esim.tiedot:
leipä 2 euroa
limpsa 1 euroa
kakku 10 euroa
limpsa 2 euroa
että löytää hinnat ja pystyy antamaan niille symbolit ja huomaa että limpsa on siellä kaksi kertaa?
Olen huomaanut että opin ohjelmointia parhaiten tutkimalla esimerkkejä ja siten ite ohjelmoimalla.
Olisin tosi kiitollinen/onnellinen jos joku jaksaisi näyttää koodin?
Se on leikepöytä. Leikkauspöytä on tämän näköinen: http://www.vivimedi.fi/surgimax.php
Dim hinnat = New Dictionary(Of String, Decimal)() Dim rivit = Clipboard.GetText().Split(ControlChars.NewLine) For Each rivi In rivit If (Not String.IsNullOrWhiteSpace(rivi)) Then Dim tiedot = rivi.Split(ControlChars.Tab) Dim Summa As Decimal If tiedot.Length <> 3 OrElse tiedot(2) <> "euroa" OrElse Decimal.TryParse(tiedot(1), Summa) Then MessageBox.Show("Rivin tiedot väärässä muodossa: " & rivi) ElseIf hinnat.ContainsKey(tiedot(0)) Then MessageBox.Show("Tuote " + tiedot(0) + " on moneen kertaan, vain ensimmäinen huomioidaan") Else hinnat.Add(tiedot(0), Summa) End If End If Next
Tai jos tykkää käyttää Regexpejä
Imports System.Text.RegularExpressions '.... Dim hinnat = New Dictionary(Of String, Decimal)() Dim re = New Regex("^(\S+)\s(\d+)\seuroa") For Each m As Match In re.Matches(Clipboard.GetText()) If hinnat.ContainsKey(m.Groups(1).Value) Then MessageBox.Show("Tuote " + m.Groups(1).Value + " on moneen kertaan, vain ensimmäinen huomioidaan") Else hinnat.Add(m.Groups(1).Value, m.Groups(2).Value) End If Next
Kiitos todella paljon avustasi. Mutta saan paljon virheilmoituksia kun laitan koodit visual basic 2010 expressiin? Ja koska en saanut sitä toimimaan en päässyt yrittämään omia sovelluksia. Siis tarkoituksena on että ohjelma osaisi toimia myös vaikka teksti olisi näin satunnaisesti:
leipä €2
limpsa €1
kakku €10
limpsa €2
(ja ilmoittaisi että siellä on limpsa kaksi kertaa.)
codemike kirjoitti:
Kiitos todella paljon avustasi. Mutta saan paljon virheilmoituksia kun laitan koodit visual basic 2010 expressiin?
Harmillista. Minkäköhän tyyppisiä virheilmoituksia sait? Mihin laitoit tuon koodin? Kannattaa tehdä vaikka nappi ja sen klikkaus-eventiin laittaa tuo koodi. Jos laitat alemman koodin tuo Imports tulee tietenkin ihan sinne tiedoston alkuun ja toi loppu taas johonkin eventiin tms subiin/funktioon.
Kiitos sain ohjelmat toimimaan mutta minulle jäi hieman epäselväksi niiden toiminta? Tarkoitus siis oli että ohjelma osaisi antaa
xxx1 leipä €2
xxxxxx limpsa €1
xx kakku €10
xxx2 limpsa €2
leikepöydälle
leipä = x, limpsa = y, kakku = e, ja ohjelmasta voisi myöhemmin huomata leipä = y = 2 ja että limpsa mainitaan kaksi kertaa.
Jos tämä olisi liian vaikeata niin sellainenkin riittäisi mikä toimisi vastaavasti mutta etukäteen olisi annettu arvot leipä = x jne. ? (enemmän kyllä kiinnostaisi ensin mainittu. Ja vielä jos ohjelma tietäisi että xxx1 ja leipä on samalla rivillä mutta se taitaa olla jo liikaa vaadittu?)
Sori nyt vaan, mutta ei tuossa sepostuksessasi ole päätä eikä häntää. Leikepöydälel voit laittaa tekstiä Clipboard.SetText() -metodilla. Et selittänyt lainkaan mitä noi xxx1, xxxxxx yms. noiden rivien aluissa on. Kerroit että leipä =x, mutta ei tuo nyt näytä hirveän järkevältä jos se tulostaisi
leipäleipäleipä1 leipä €2
leipäleipäleipäleipäleipäleipä limpsa €1
jne.
Ainakin tuo ensimmäinen versioni oli hyvin yksinkertainen. Se vain jakoi leikepöydältä jaetun tekstin riveihin ja sitten käsitteli kunkin rivin erikseen jakamalla sen osiin välilyönin perusteella. Tulokset se tallesti dictionaryyn, joka siis on tietorakenne, joka voi sisältää halutun tyyppisiä arvoja joita voi hakea halutun tyyppisellä avaimella. Esimerkissä avain oli merkkijono (tuotten nimi) ja arvo olisi desimaaliluku (hinta).
Eli varmastikin siitä pystyisit hyvin helposti lähteä kehittämään asiaa eteenpäin, jos vaan kiinnostusta löytyy. Kiinnostus tarkoittaa sitä, että myös itse haluaa nähdä vähän vaivaa asian eteen.
Sitten jos tulee ongemia jossain asiassa, niin yritä kysyä silleen, että kysymys on selkeä ja yksikäsitteinen.
codemike kirjoitti:
mutta se taitaa olla jo liikaa vaadittu
Jos sen ohjelman täytyy osata lukea ajatuksia, niin sitten se on liikaa vaadittu. Muuten ei. Yleisesti minkäänlaisen tietojen käsittelyn tekeminen ei ole mahdotonta, jos vaan ei vaadita että ohjelman pitäisi kehittää informaatiota tyhjästä. Esimerkiksi ensi viikon lottonumeroita on turha yrittää kehittää ohjelmallisesti.
Kiitos avusta mietiskelen rauhassa. Mutta ihan perus asioihin mennäkseni niin kun viiimeksi aikoinaan ohjelmoin enemmän se oli aikaa jolloin oli rivinumerot. Nyt innostuin funktioista ja huomasin ne hyväksi ja luulin jo tajunneeni ohjelmoinnin idean että hypätään funktiosta funktioon. Mutta siinähän käy nopeasti niin että Recursion level exceeded koska jos hyppää funktiosta toiseen se jää tavallaan päälle ja kun siihen palataan uudestaan se luo copyn. Onko tälläinen ongelma ratkaistavissa vai mikä on nykyisen ohjelmoinnin idea?
codemike kirjoitti:
Nyt innostuin funktioista ja huomasin ne hyväksi ja luulin jo tajunneeni ohjelmoinnin idean että hypätään funktiosta funktioon. Mutta siinähän käy nopeasti niin että Recursion level exceeded
No, aika monta sisäkkäistä funktiokutsua saat tehdä ennen kuin tulee Recursion level exceeded. Ehkä olet ymmärtänyt jotain väärin. Siis idea toki on, että funktiot kutsuu funktioita jotka kutsuu funktioita, mutta niistä on välillä tarkoitus mennä poiskin.
Kokeilin tuossa tehdä funktion joka kutsui itseään ja 14300 rekursiota ehti tulla ennen stack overflowta. Normaalissa ohjelmoinnissa tuskin koskaan mennään yli 100 rekursion (ellei nimemomaan käytetä jotain rekursiivista algoritmia)
Ehkä jos laitat jonkun tekemäsi ohjelman joka saa aikaan recursion level exceededin, niin voisin katsoa jos sen saisi korjattua.
Funktioilla ei ole tarkoitus hyppiä ohjelman osasta toiseen, vaan ideana on, että jokainen funktio (tai aliohjelma) tekee jonkin asian ja loppuu sitten.
Sub tee_yksi_asia() ' Tee jotain pientä End Sub Sub tee_toinen_asia() ' Tee jotain muuta pientä End Sub Sub tee_kolmas_asia() ' Tee vielä jotain pientä End Sub Sub tee_monta_asiaa() tee_yksi_asia() tee_toinen_asia() tee_kolmas_asia() End Sub
"Siis idea toki on, että funktiot kutsuu funktioita jotka kutsuu funktioita, mutta niistä on välillä tarkoitus mennä poiskin." Miten niistä pääsee pois ettei se tavallaan jää päälle jos sieltä haluaa toiseen funktioon ehtolauseen kautta? tai voiko ne mahdollisesti nollata? Esimerkiksi jos edellisessä pätkässä palataan alkuun eli vaikka halutaan tarkkailla muuttuvia muuttujia loopissa niin eihän siinä kauaa mene kun muisti täyttyy vai ovatko ohjelmointi kielten muistipituus erinlainen? Esim. jos seuraavassa pätkässä jonka sain aikaisemmin tätä kautta haluan then'in tai if'in täyttyessä toiseen funktioon ja vielä palatakkin jossain vaiheessa ja niin edespäin vai miten voisin mahdollisesti muuten tehdä vastaavan? Ja kerran vielä kiitos että jaksatte vastailla.
Module Module1 Sub Main() Console.Clear() Console.Write("Kirjoita analysoitava teksti: ") Dim Teksti = Console.ReadLine() If SisältääKirosanan(Teksti) Then Console.WriteLine("Lause sisältää yhden tai useamman kirosanan.") Else Console.WriteLine("Lauseesta ei löytynyt kirosanoja.") Console.WriteLine("Vittu") End If Threading.Thread.Sleep(1000) End Sub Private Function SisältääKirosanan(ByVal teksti As String) As Boolean Dim Kirosanat = New String() {"vittu", "saatana", "perkele", "paska", "jumalauta", "helvetti", "fuck", "shit", "wtf", "vitu"} For Each Kirosana In Kirosanat If teksti.ToLower.Contains(Kirosana) Then Return True End If Next Return False End Function End Module
lainaus:
Miten niistä pääsee pois ettei se tavallaan jää päälle jos sieltä haluaa toiseen funktioon ehtolauseen kautta?
Funktiosta pääsee pois joko Returnilla tai ihan vaan sillä että se funktio loppuu. Ja VB:ssä on vielä Exit Sub / Exit Function. Tosin en kyllä suosittele käyttämään niitä nyt kun Return on tuettu.
Toki funktion sisältä voi kutsua toista funktiota, mutta kun siitä toisesta funktiosta palataan, niin ei se jää mihinkään roikkumaan.
En nyt tiedä millä tavalla tuo sinulle aikaisemmin kirjoittamani koodi liittyy aiheeseen, mutta siinähän tuo SisältääKirosanan funktio nimenomaan poistuu palauttaen joko True tai False, jolloin se ei jää "roikkumaan" ja sitä kutsunut Main-funktio (tai no VB tapauksessa "Sub") osaa toimia saamansa vastauksen mukaisesti.
Eli esimerkiksi tuolla ohjelmalla ei saa aikaiseksi liian syvää rekursiota.
Tässä on AutoIt basicin kaltaista selvää helppoa kieltä (visual basic selosteella) mitä tarkoitan ja tässä tapahtuu ylitys lopulta kuten varmaan muillakin ohjelmointi kielillä eli mitä olisi tehtävissä? (Funktiokutsut voisivat tietysti myös olla muihin funktioihin mutta niiden pitäisi lopulta kuitenkin kiertää jatkuvasti.)
Main() Func Main() ; Sub Main() $clipboardContents = Clipget() $Text = $clipboardContents; Console.Write("Write text: ") ; Dim Text = Console.ReadLine() If ContainsSuchword($Text) Then ;If ContainsSuchword(Text) Then MainB() ;Console.WriteLine("There is one or more such words") Else MainB() EndIF EndFunc Func ContainsSuchWord($Text) ;Private Function ContainsSuchword(ByVal text As String) As Boolean Dim $Suchwords[3] = ["sana1", "sana2", "sana3"] For $i = 0 To UBound($Suchwords)-1 ;For Each Suchword In Suchwords If StringInStr($Text, $Suchwords[$i]) Then ;If text.ToLower.Contains(Suchword) Then Return True EndIf Next Return False EndFunc Func MainB() $clipboardContentsB = Clipget() $TextB = $clipboardContentsB If ContainsSuchwordB($TextB) Then ;If ContainsSuchwordB(Text) Then Main() Else Main() EndIF EndFunc Func ContainsSuchWordB($TextB) ;Private Function ContainsSuchwordB(ByVal text As String) As Boolean Dim $SuchwordsB[3] = ["sana1", "sana2", "sana3"] For $i = 0 To UBound($SuchwordsB)-1 ;For Each Suchword In Suchwords If StringInStr($TextB, $SuchwordsB[$i]) Then ;If text.ToLower.Contains(Suchword) Then Return True EndIf Next Return False EndFunc
Gyaah. Ei kooditageja, ja sitten vielä kahta "kieltä" sekaisin.
Noh, tuossa nyt on kuitekin aivan selvä vika se, että kutsut MainB:stä Mainia.
Tässä nyt toiminnallisesti sama kuin yllä oleva koodisi mutta niin, että ei aiheudu rekursioylivuotoa.
Module Module1 Sub Main() Do Dim clipboardContents = Clipboard.GetText() Dim Text = clipboardContents 'Console.Write("Write text: ") 'Text = Console.ReadLine() If ContainsSuchword(Text) Then MainB() 'Console.WriteLine("There is one or more such words") Else MainB() End If Loop End Sub Private Function ContainsSuchword(ByVal text As String) As Boolean Dim Suchwords = {"sana1", "sana2", "sana3"} For Each Suchword In Suchwords If text.ToLower.Contains(Suchword) Then Return True End If Next Return False End Function Private Sub MainB() Dim clipboardContentsB = Clipboard.GetText() Dim TextB = clipboardContentsB If ContainsSuchwordB(TextB) Then Else End If End Sub Private Function ContainsSuchwordB(ByVal text As String) As Boolean Dim SuchwordsB = {"sana1", "sana2", "sana3"} For Each Suchword In SuchwordsB If text.ToLower.Contains(Suchword) Then Return True End If Next Return False End Function End Module
En edes yritä keksiä mitään järkevää selitystä sille, että tuolla on nuo B-subit/funktiot, jotka kuitenkin on identtisiä.
Tämä on vaan testiohjelma periaatteelle. Mutta ongelma ei kuitenkaan korjaantunut kun laitoin vastaavan AutoIt'iin. Siellä ei ole loop käskyä mutta vastaava tilanne tulee jos laitan sinne niinkun alla $i = 0, Do, $i = $i + 1
Until $i = 10. ? Se pitäisi tulla myös visual basicissa vaikka en päässyt sitä kokeilemaan koska tulee virhe ilmoitus ennen ohjelman päälle laittoa 'clipboard' is not declared.
$i = 0 Main() Func Main() ; Sub Main() Do $clipboardContents = Clipget() $Text = $clipboardContents; Console.Write("Write text: ") ; Dim Text = Console.ReadLine() If ContainsSuchword($Text) Then ;If ContainsSuchword(Text) Then MainB() ;Console.WriteLine("There is one or more such words") Else ; Else MainB() EndIF $i = $i + 1 Until $i = 10 EndFunc Func ContainsSuchWord($Text) ;Private Function ContainsSuchword(ByVal text As String) As Boolean Dim $Suchwords[3] = ["sana1", "sana2", "sana3"] For $i = 0 To UBound($Suchwords)-1 ;For Each Suchword In Suchwords If StringInStr($Text, $Suchwords[$i]) Then ;If text.ToLower.Contains(Suchword) Then Return True EndIf Next Return False EndFunc Func MainB() $clipboardContentsB = Clipget() $TextB = $clipboardContentsB If ContainsSuchwordB($TextB) Then ;If ContainsSuchword(Text) Then Main() Else Main() EndIF EndFunc Func ContainsSuchWordB($TextB) ;Private Function ContainsSuchword(ByVal text As String) As Boolean Dim $SuchwordsB[3] = ["sana1", "sana2", "sana3"] For $i = 0 To UBound($SuchwordsB)-1 ;For Each Suchword In Suchwords If StringInStr($TextB, $SuchwordsB[$i]) Then ;If text.ToLower.Contains(Suchword) Then Return True EndIf Next Return False EndFunc
codemike, opettelemalla kooditagien käytön viesteissäsi saat todennäköisemmin neuvoja. Klikkaa Ohjeet viestien kirjoitukseen -linkkiä tältä samalta sivulta.
codemike kirjoitti:
Tämä on vaan testiohjelma periaatteelle. Mutta ongelma ei kuitenkaan korjaantunut kun laitoin vastaavan AutoIt'iin.
Et laittanut vastaavaa kuin osittain. Olisi huomattavasti kivempaa vastailla, jos vaivautuisit myös lukemaan mitä kirjoitetaan...
Grez kirjoitti:
Noh, tuossa nyt on kuitekin aivan selvä vika se, että kutsut MainB:stä Mainia.
codemike kirjoitti:
Func MainB() $clipboardContentsB = Clipget() $TextB = $clipboardContentsB If ContainsSuchwordB($TextB) Then ;If ContainsSuchword(Text) Then Main() Else Main() EndIF EndFunc
Tuon siis pitäisi olla:
Func MainB() $clipboardContentsB = Clipget() $TextB = $clipboardContentsB If ContainsSuchwordB($TextB) Then ;If ContainsSuchword(Text) Then Else EndIF EndFunc
Varsinaiseen virheilmoitukseen en osaa sanoa. Laittamassasi koodissa ei lue kertaakaan Clipboard, joten en tiedä miksi AutoIT siitä valittaisi.
Virheilmoitus tuli siis Visual Basic Express'illä. Mutta niinkuin sanon olen nöyrästi kiitollinen kaikesta avusta. Tuota muutostasi en huomannut mutta ongelmana siis on kutsua toista funkiota toisesta funktiosta ilman muistin ylitystä lopulta. Uskon siis Metabolix'in vastaukseen että se ei ole mahdollista ennen kun toisin näytetään. Sillä tuossa sinun esimerkissähän MainB() on kuollut (then ja else'ä ei saa ohjattua mihinkään).
codemike kirjoitti:
Tuota muutostasi en huomannut mutta ongelmana siis on kutsua toista funkiota toisesta funktiosta ilman muistin ylitystä lopulta.
Tietenkin muisti loppuu aikanaan, jos tekee ikuisen rekursion. Pointti on, että mitään hyötyä sellaisesta esimerkissäsi ei ole. Kuten kirjoitin: "Tässä nyt toiminnallisesti sama kuin yllä oleva koodisi mutta niin, että ei aiheudu rekursioylivuotoa."
Eli siis, laittamani koodi tekee täsmälleen saman kuin alkuperäinen koodisi, mutta se ei turhaan kutsu Mainia.
codemike kirjoitti:
MainB() on kuollut (then ja else'ä ei saa ohjattua mihinkään).
Sinähän siitä kuolleen teit, kirjoitin vain saman toiminnallisuuden järkevämmin. Omassa koodissasikaan ei ole mitään eroa suoritetaanko if vai else -osio. Toki jos se ilahduttaa sinua, niin voit laittaa molempiin "Return". Lopputulos ei muutu, koska funktion loppuminen aiheuttaa joka tapauksessa returnin.
codemike kirjoitti:
Uskon siis Metabolix'in vastaukseen että se ei ole mahdollista ennen kun toisin näytetään.
Kukaan ei ole väittänytkään että ikuinen rekursio olisi mahdollinen. Totesin vaan että sellaiselle ei myöskään koskaan ole tarvetta:
Grez kirjoitti:
Normaalissa ohjelmoinnissa tuskin koskaan mennään yli 100 rekursion (ellei nimemomaan käytetä jotain rekursiivista algoritmia)
Omaa tyhmyyttähän se oli olisin voinut laittaa paremman esimerkin. Elikkä asia on siis niin että funktio voi antaa jonkun arvon mutta siitä ei voi siis siirtyä toiseen funktioon aiheuttamatta lopulta muistin ylitystä.
Tietenkin voit käyttää vanhan aikaista goto-järjestelmää eli
'Ei testattu, mutta idean varmaan saa Sub main() Alustus: Dim n as Integer = 0 'Hypätään kohtaan Toka goto Toka Eka: 'Tokana tapahtuu tää ja sit hypätään alustukseen Console.writeline(n) goto Alustus Toka: 'Tää taapahtuu ensin ja sitten hypätään kohtaan Eka Console.writeline(n) n = 100 goto Eka End Sub
Kiitti mutta AutoIt'ssä ei ole enää goto käsky mukana mutta saan kyllä tehtyä ohjelmani muutenkin.
codemike kirjoitti:
Elikkä asia on siis niin että funktio voi antaa jonkun arvon mutta siitä ei voi siis siirtyä toiseen funktioon aiheuttamatta lopulta muistin ylitystä.
Voi siirtyä toiseen funktioon, josta voi siirtyä kolmanteen, jonka loputtua suoritus palaa toiseen, jonka loputtua palataan ensimmäiseen. Näin esimerkkinä.
Toki jos et koskaan anna funktion suorittaa itseään loppuun asti, vaan kutsut aina seuraavaa joka tasolla, niin jossain vaiheessa suoritus päättyy virheeseen.
Tein tällaisen hienon kuvan: http://grez.info/putka/kutsut.png
Siinä on kolmen värisiä nuolia:
Punainen nuoli:
Funktiokutsu
Siirtää suorituksen toiseen funktioon ja laittaa lähtöpaikan muistiin, että siihen voitaisiin palata
Vihreä nuoli:
Funktiosta palaaminen, eli jokin seuraavista
- Return
- Exit Function
- Exit Sub
- End Function
- End Sub
Tämä palauttaa suorituksen paikkaan, josta funktiota kutsuttiin. Tallennettu paikka voidaan poistaa muistista, eli muistia vapautuu.
Sininen nuoli:
Toistorakenne, eli esimerkiksi:
- For
- Loop
- While
- Do
Tämän ei tarvitse muistaa, mistä kohti toistorakennetta palattiin takaisin toiston alkuun, joten se ei kuluta eikä vapauta muistia.
Yhteenveto:
Jos käytät punaisia nuolia, pitää välillä käyttää myös vihreitä nuolia. Jos ohjelman suoritus pyörii ympyrässä, missä vaan tehdään punaista koko ajan, niin resurssit loppuu väkisinkin.
Kiitos kuvasta. Ja muuten ohjelmoinnista mainitakseni se on mukavaa kun on projekti joka kiinnostaa ja löytää ratkaisuja siihen. Voi olla kiinnostavampi kirjallisuuteenkin paneutua kun on perus asiat hallinnassa jotka ei tuntunu edes kirjallisuudesta heti avautuvan.
Aihe on jo aika vanha, joten et voi enää vastata siihen.