Bereik gegevenstype

Moderators: jkien, Xilvo

Reageer
Gebruikersavatar
Berichten: 3.963

Bereik gegevenstype

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.)

Code: Selecteer alles

(...)

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?
"Success is the ability to go from one failure to another with no loss of enthusiasm" - Winston Churchill

Gebruikersavatar
Berichten: 829

Re: Bereik gegevenstype

Kravitz schreef: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.)

Code: Selecteer alles

(...)

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:

Code: Selecteer alles

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):

Code: Selecteer alles

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):

Code: Selecteer alles

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.
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."

--Vladimir Lenin-- (Владимир Ильич Ульянов)

Gebruikersavatar
Berichten: 3.963

Re: Bereik gegevenstype

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

Berichten: 473

Re: Bereik gegevenstype

Kravitz schreef: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?

Code: Selecteer alles

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

Gebruikersavatar
Berichten: 829

Re: Bereik gegevenstype

Kravitz schreef: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.com/forum/showthread.php...7624&page=1

goodluck!
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."

--Vladimir Lenin-- (Владимир Ильич Ульянов)

Gebruikersavatar
Berichten: 3.963

Re: Bereik gegevenstype

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

Gebruikersavatar
Berichten: 829

Re: Bereik gegevenstype

Kravitz schreef: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.
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."

--Vladimir Lenin-- (Владимир Ильич Ульянов)

Berichten: 473

Re: Bereik gegevenstype

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:

Code: Selecteer alles

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)

Code: Selecteer alles

Option Explicit
gebruik bij elke module. Een niet gedeclareerde variabel zal een fout genereren.

2)

Code: Selecteer alles

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??

Gebruikersavatar
Berichten: 3.963

Re: Bereik gegevenstype

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

Reageer