Springen naar inhoud

Bereik gegevenstype


  • Log in om te kunnen reageren

#1

Kravitz

    Kravitz


  • >1k berichten
  • 4042 berichten
  • Moderator

Geplaatst op 22 oktober 2010 - 16:05

Hallo allemaal,

Ik zit met een probleempje bij het oplossen van een oefening in VBA.
Het gaat over EG nummers van chemische stoffen. Deze bestaan uit iets in de vorm van "CCC-CCC-R". Waarbij iedere C voor een getal staat en R voor en controle nummer.
Omdat ik verplicht ben een 'string' als input te gebruiken besloot ik de eerste 3 getallen uit de input te knippen. Idem voor de volgende drie getallen.

c123 = eerste drie getallen
c456 = getal 4, 5 en 6

Nu wil ik alles samenvoegen tot een nieuw getal, van de vorm c123456. Jammer genoeg krijg ik steeds een overloop.
Volgens mij heeft het te maken met het bereik van de variabele. Eerst gebruikte ik 'Integer', dit was te klein, maar nu zou alles toch moeten werken via een 'Long'?

(Zie stukje code voor de manier waarop ik dit doe)
(Vermenigvuldigen met 1000 doe ik zodat het verkregen getal meer op de input gaat lijken.)

(...)
Dim nieuwnr As Long

egnr = InputBox("Geef het EG nummer op")

c123 = Mid(egnr, 1, 3)
c456 = Mid(egnr, 5, 3)

nieuwnr = (c123 * 1000) + c456

Dus in het geval van 200-001-8 krijg ik voor:
  • c123 = 200
  • c456 = 1
  • nieuwnr = 200001
Wat is er mis?

Veranderd door Kravitz, 22 oktober 2010 - 16:08

"Success is the ability to go from one failure to another with no loss of enthusiasm" - Winston Churchill

Dit forum kan gratis blijven vanwege banners als deze. Door te registeren zal de onderstaande banner overigens verdwijnen.

#2

Vladimir Lenin

    Vladimir Lenin


  • >250 berichten
  • 829 berichten
  • Ervaren gebruiker

Geplaatst op 22 oktober 2010 - 16:19

Hallo allemaal,

Ik zit met een probleempje bij het oplossen van een oefening in VBA.
Het gaat over EG nummers van chemische stoffen. Deze bestaan uit iets in de vorm van "CCC-CCC-R". Waarbij iedere C voor een getal staat en R voor en controle nummer.
Omdat ik verplicht ben een 'string' als input te gebruiken besloot ik de eerste 3 getallen uit de input te knippen. Idem voor de volgende drie getallen.

c123 = eerste drie getallen
c456 = getal 4, 5 en 6

Nu wil ik alles samenvoegen tot een nieuw getal, van de vorm c123456. Jammer genoeg krijg ik steeds een overloop.
Volgens mij heeft het te maken met het bereik van de variabele. Eerst gebruikte ik 'Integer', dit was te klein, maar nu zou alles toch moeten werken via een 'Long'?

(Zie stukje code voor de manier waarop ik dit doe)
(Vermenigvuldigen met 1000 doe ik zodat het verkregen getal meer op de input gaat lijken.)

(...)
Dim nieuwnr As Long

egnr = InputBox("Geef het EG nummer op")

c123 = Mid(egnr, 1, 3)
c456 = Mid(egnr, 5, 3)

nieuwnr = (c123 * 1000) + c456

Dus in het geval van 200-001-8 krijg ik voor:
  • c123 = 200
  • c456 = 1
  • nieuwnr = 200001


Wat is er mis?

Volgens mij werkt je parser gewoon mis, een integer gaat in theorie tot iets van een 2 miljard. Dus kun je 8 cijfers (ik neem aan dat je cijfers, en geen getallen bedoelt) zeer zeker opslaan in een integer. Ik zou je aanraden de boel te parsen met behulp van een Regex.

In java wordt dat dus:

Pattern p = Pattern.compile("([0-9][0-9][0-9])-([0-9][0-9][0-9])-([0-9])");
//haal data uit de expressie die je invoert
Matcher m = p.matcher(invoer);
m.find();
if(!m.matches())
	throw new Exception("Ongeldige invoer!");
//analyseer data
int c123 =Integer.parseInt(m.group(1));
int c456 =Integer.parseInt(m.group(2));
int r =Integer.parseInt(m.group(3));
int uitvoer = c123*1000+c456;

ofwel volgend klein demonstratieprogrammaatje (leest de command line uit en geeft getal terug):
package testen;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

	/**
	 * @param args the command line arguments
	 */
	public static void main(String[] args) throws Exception {
		//invoer
		InputStreamReader isr = new InputStreamReader(System.in);
		BufferedReader in = new BufferedReader(isr);
		String invoer = in.readLine();
		//regex bouwen
		Pattern p = Pattern.compile("([0-9][0-9][0-9])-([0-9][0-9][0-9])-([0-9])");
		//haal data uit de expressie die je invoert
		Matcher m = p.matcher(invoer);
		m.find();
		if(!m.matches())
			throw new Exception("Ongeldige invoer!");
		//analyseer data
		int c123 =Integer.parseInt(m.group(1));
		int c456 =Integer.parseInt(m.group(2));
		int r =Integer.parseInt(m.group(3));
		int uitvoer = c123*1000+c456;
		System.out.println(String.format("het getal is %s",uitvoer));
	}

}

Dit kwam er bij mij uit (eerste lijn is mijn invoer):
317-483-2
het getal is 317483

EDIT: verder is het ontvangen van data met behulp van substrings zonder voorafgaande controle van de structuur erg af te raden, een regex lost dat probleem op. In .NET heb je de klasse Regex <-> Java's Pattern en met een min of meer gelijklopende implementatie,

succes.

Veranderd door Vladimir Lenin, 22 oktober 2010 - 16:26

"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."
--Vladimir Lenin-- (Владимир Ильич Ульянов)

#3

Kravitz

    Kravitz


  • >1k berichten
  • 4042 berichten
  • Moderator

Geplaatst op 22 oktober 2010 - 16:27

Volgens mij werkt je parser gewoon mis, een integer gaat in theorie tot iets van een 2 miljard

Een integer is toch maar 2 bytes dus van -32768 tot 32767. Dit zegt mijn cursus toch ;)
Een long zou dan weer 4 bytes zijn ofwel van -2.147.483.648 tot 2.147.483.647

Jij doet het in Java werkt zoiets ook in VBA (Microsoft Visual Basic)?
"Success is the ability to go from one failure to another with no loss of enthusiasm" - Winston Churchill

#4

mcs51mc

    mcs51mc


  • >250 berichten
  • 470 berichten
  • Ervaren gebruiker

Geplaatst op 22 oktober 2010 - 19:35

Dus in het geval van 200-001-8 krijg ik voor:

  • c123 = 200
  • c456 = 1
  • nieuwnr = 200001
Wat is er mis?


Niets ;)
200 * 1000 + 1 is toch 200001
Dus wat is het probleem ;)

Trouwens waarom ga je over naar longs?
Je kan toch ook gewoon je tekst herschikken? Of zie ik iets over het hoofd?



Option Explicit

Private Sub Trial()
Dim strInput		As String
Dim lngData1		As Long
Dim lngData2		As Long
Dim lngNew		  As Long
Dim strNew		  As String


	strInput = "200-001-8"
	
	lngData1 = CLng(Mid(strInput, 1, 3))
	lngData2 = CLng(Mid(strInput, 5, 3))
	lngNew = lngData1 * 1000 + lngData2
	
	strNew = (Mid(strInput, 1, 3)) & (Mid(strInput, 5, 3))
	
	Debug.Print lngData1, lngData2, lngNew, strNew

End Sub

Veranderd door mcs51mc, 22 oktober 2010 - 19:43


#5

Vladimir Lenin

    Vladimir Lenin


  • >250 berichten
  • 829 berichten
  • Ervaren gebruiker

Geplaatst op 22 oktober 2010 - 22:15

Een integer is toch maar 2 bytes dus van -32768 tot 32767. Dit zegt mijn cursus toch ;)
Een long zou dan weer 4 bytes zijn ofwel van -2.147.483.648 tot 2.147.483.647

Jij doet het in Java werkt zoiets ook in VBA (Microsoft Visual Basic)?

Hangt af van de taal

in .NET is:

een short 16 bit (2 byte) dus -32,768 tot 32,767
een int 32 bit (4 byte) dus -2,147,483,648 tot 2,147,483,647
een long 64 bit (8 byte) dus -9,223,372,036,854,775,808 tot 9,223,372,036,854,775,807

in C en C++ zijn deze echter anders gedefinieerd.

Je kan het ook in Visual Basic doen, al ben ik eerlijk gezegd geen VBA expert (en om eerlijk te zijn haat ik VBA, alleen al omwille van de typografie). Er bestaan equivalente klasses die hetzelfde doen. Zo kan je Pattern vervangen door Regex. De rest ken ik niet helemaal vanbuiten.

Dit artikel geeft een opzet: http://www.ozgrid.co...p...7624&page=1

goodluck!
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."
--Vladimir Lenin-- (Владимир Ильич Ульянов)

#6

Kravitz

    Kravitz


  • >1k berichten
  • 4042 berichten
  • Moderator

Geplaatst op 22 oktober 2010 - 22:29

Okť, hartelijk dank Vladimir Lenin, ik ga wat uitproberen!

@mcs51mc

Wel je start dus van "200-001-8" wat je inleest als een string. Vervolgens haal ik 200 en 001 eruit met de functie "mid" en ken die ieder toe aan een variabele. Nu wil ik een nieuwe variabele creŽren van de vorm c123456 = variabele 1 * 1000 + variabele 2.
Voor het gegevenstype van c123456 kies ik Long maar echter geeft dit een overflow. Mijn vraag was waarom?
(ik koos long omdat integer te klein was in VBA)
Volgens Vladimir Lenin zou het dus aan de parser liggen.

Duidelijker? ;)
"Success is the ability to go from one failure to another with no loss of enthusiasm" - Winston Churchill

#7

Vladimir Lenin

    Vladimir Lenin


  • >250 berichten
  • 829 berichten
  • Ervaren gebruiker

Geplaatst op 22 oktober 2010 - 23:16

Okť, hartelijk dank Vladimir Lenin, ik ga wat uitproberen!

@mcs51mc

Wel je start dus van "200-001-8" wat je inleest als een string. Vervolgens haal ik 200 en 001 eruit met de functie "mid" en ken die ieder toe aan een variabele. Nu wil ik een nieuwe variabele creŽren van de vorm c123456 = variabele 1 * 1000 + variabele 2.
Voor het gegevenstype van c123456 kies ik Long maar echter geeft dit een overflow. Mijn vraag was waarom?
(ik koos long omdat integer te klein was in VBA)
Volgens Vladimir Lenin zou het dus aan de parser liggen.

Duidelijker? ;)


Wat is btw het type van c123 en c456, ints of strings?

hmmm... blijkbaar werkt VBA toch met die vree,de range, maar anyway een Long moet het kunnen parsen, dus dan nog loopt er iets mis. Hoe behandelt VBA arithmetic op ints?

Als je een int hebt en je vermenigvuldigt die met 1000, blijft het dan een int of niet. Anders zou ik eerst de c123 en c456 naar longs omzetten.

Veranderd door Vladimir Lenin, 22 oktober 2010 - 23:19

"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."
--Vladimir Lenin-- (Владимир Ильич Ульянов)

#8

mcs51mc

    mcs51mc


  • >250 berichten
  • 470 berichten
  • Ervaren gebruiker

Geplaatst op 23 oktober 2010 - 08:10

Twee vragen voor Kravitz
1) Vertrekkend van "200-001-8"; moet het antwoord "c200001" zijn of gewoon "200001"?
2) Je resultaat, moet het een getal zijn (int of lng laat ik in het midden) of mag het ook tekst zijn? Indien je er verder niet meer mee rekent, zou ik het in string vorm laten.

Dan nog dit over:
c123 = Mid(egnr, 1, 3)
Aangezien je "c123" niet gedeclareerd hebt, krijgt "c123" hetzelfde datatype als "egnr", dus string, dus kan je er verder niet mee rekenen.

Vandaar dat ik:
1)
Option Explicit
gebruik bij elke module. Een niet gedeclareerde variabel zal een fout genereren.


2)
lngData1 = CLng(Mid(strInput, 1, 3))
De string expliciet nog converteer naar een long met de "CLng" instructie. Niets aan het toeval overlaten ;)


De code die ik gisteren poste lost je probleem toch op of niet??

Veranderd door mcs51mc, 23 oktober 2010 - 08:12


#9

Kravitz

    Kravitz


  • >1k berichten
  • 4042 berichten
  • Moderator

Geplaatst op 23 oktober 2010 - 10:25

Dag mcs51mc!

Vertrekkend van "200-001-8"; moet het antwoord "200001" zijn. Het is de bedoeling dat ik er later nog mee ga rekenen, dus liefst een getal.

Verder begrijp ik wat je bedoelt met de 'Option Explicit', deze gebruik ik zelf ook maar ik poste slechts een stukje van de programmacode in mijn eerste bericht. c123 is dus wel degelijk gedeclareerd als een getal.

De string expliciet nog converteer naar een long met de "CLng" instructie. Niets aan het toeval overlaten ;)

Dit had ik nog niet gedaan, na aanpassen werkt alles perfect!

Hartelijk dank! ;)
"Success is the ability to go from one failure to another with no loss of enthusiasm" - Winston Churchill





0 gebruiker(s) lezen dit onderwerp

0 leden, 0 bezoekers, 0 anonieme gebruikers

Ook adverteren op onze website? Lees hier meer!

Gesponsorde vacatures

Vacatures