Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Searching for range in a String 3

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi All,
I'm having a problem trying to search a string to determine the presense of a value, which could be a range.
So for instance, if I have the following string:

A23: M2 123 456 7890

And I want to determine if it contains, non-numeric data (so the A and the M as well as the : would be identified, but I don't need to know the specific character.

I've tried several combinations of OCCURS, AT, BETWEEN CHR() but can't seem to get one that works, due to the "Range" at hand.

If we called the string lcText My expression looked something like:

lnRetVal = OCCURS(BETWEEN(lcText,CHR(65),CHR(90)),lcText)
lnRetVal = AT(BETWEEN(lcText,CHR(65),CHR(90)),lcText,1)

(in these cases I was just looking for Uppercase Alpha as that will do)

But they fail, and the BETWEEN I think is the problem, but I don't see any other function that would do it?
Is this possible, or do I need to tear the whole string down byte by byte and examine its ASC value?

I tested with both to try to get BETWEEN to work with the string search, but what I'm really after is the AT() position of the first occurrence of a "alpha" character.
I realize in this example, I should be using UPPER(lcText), but the string I was testing with was already uppercase, so I was just trying to make it work in test environment before I put it in the code.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Vilhelm,
I like your point about EMPTY vs LEN. It can also be expressed as IF m.yy = "" -> evaluates to .T. In your example. But IF m.yy == "" will Fail.

Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Let me even be stronger about EMPTY than both of you: EMPTY is neither fastest nor most thoroughly about determining emptyness.

Empty accepts strings containng ASCII code 9,10,13 and 32:
Code:
lcEmpty=""
For lnASCII = 0 to 255
  If Empty(lcEmpty+Chr(lnASCII))
     lcEmpty = lcEmpty+Chr(lnASCII)
  EndIf
EndFor
For lnLen = Len(lcEmpty) to 1 Step -1
    ? Asc(Right(lcEmpty,lnLen))
Endfor

Therefor it may be okay, if you'll want to allow these chars besides digits. Yoy may also replace these chars to remove them too and then can still check with LEN().

LEN() is faster, as it simply looks into the length attribute of the C struct for general variables internal to the VFP runtime:
[tt]typedef struct {
char ev_type;
char ev_padding;
short ev_width;
unsigned ev_length;
long ev_long;
double ev_real;
CCY ev_currency;
MHandle ev_handle;
unsigned long ev_object;
} Value;[/tt]

Well, to be precise this is the definition for variable values you get from the LCK (library construction kit), but should resemble closely how VFP internally stores a variable. The ev_length attribute or member is the length of a string value and so LEN() just needs to look in there, in the same manner as RECCOUNT() only looks into the DBF header and doesn't really count records. This allows strings to contain anything, even chr(0), there is no termination character, there simply is a handle to some memory where the string begins and has a certain length.

EMPTY on the other hand needs to process the chars until it finds something aside of the allowed four whitespace char, with 0 length it also has few things to do, the loop on the string memory then has 0 iterations. But on he other hand there is chr(7) also not having any visual representation, besides that backspace, vertical tab and many more chars of ASCII/ANSI.

While EMPTY() is better "speaking" - saying or advertising what it does - it's a function to rather avoid than to use.

Bye, Olaf.


 
I really never use LEN() to determine if there is a value stored unless I'm testing LEN overall, for some other reason. Usually I use LEN to get the length value of something that I use along with RIGHT, LEFT or SUBSTR in combination with LEN to extract data I need from itself.
Never thought of using LEN to determine "Emptiness". I would test with IF val = "" or EMPTY().
Regarding the "SPEED", that's one of those things I worried about when I was using a Pentium... but on the blazing fast machines of today (even the slowest) so long as "EMPTY" check isn't part of a loop I wouldn't stress if it took 50 milliseconds for one and 450miliseconds for the other to execute... But it's good to know for those times when you ARE working in LOOPs that have tens of thousands or even much greater cycles. Then those milliseconds can cut hours off of processing.

My current application has no such burdens, and for the foreseeable future isn't likely to have.

One question, where did you find that structure for LEN? It would be interesting to see some of VFPs other functions.


Best Regards,
Scott
ATS, CDCE, CTIA, CTDC

"Everything should be made as simple as possible, and no simpler."[hammer]
 
It comes from the LCK documentation, and while I don't have that myself, it's what Chrstof Wollenhaupt says in the overall very intersting article How Foxpro works internally. It's not the struct of LEN its the struct of values/variables.

Anyway, indeed EMPTY is even fast as long as you don't have some whitespace followed by non whitespace. It's never a point for single lines executing, but even if it's a single line, how are you sure it always will be and not become part of a function, which years later is called in a loop. The same goes for mdots, you can also avoid the effect of prioritized fields with SELECT 0, but when do you have code not working on some current table or cursor? mdots is not only covering the case you have memvars same as your table fields. In tools for generally working on any database and tables like a query tool or report engine or the infamous data explorer within the task pane you should be defensive against anything which might occur. Even if the case of field name lOrange and variabel name loRange is rather ridiculous, the case that happened was a field called cName cause trouble, which it wouldn't, if a variable in data explorer code woud have been named lcName instead of cName. No excuse, in case the variable would have been named after naming convention the problematic case of a field lcname could also occur.

I always felt embarrased by people stating they always use mdots, but provably don't do in code shared in forums. It has one more usefulness, it allows for intellisense picking of defined variables, but that has limited use in the command window for variables currently in memory. If you write LOCAL lnX, lnY in the code editor, the m. does not show these variables, if you use the ZLOC intellisense code you get variables, but their name will not be mdot prefixed.

The strongest argument is actually this kind of discussions about using or not using mdots and the general unawareness about it you always have to explain it in the moment you post code with mdots. And combined with how few times (once!) this really was casugin a production problem compared with syntax errors, wrong queries, wrong data, inefficient indexing (thousands) it's not a matter of interest to me.

I made a different decision when learning about NOFILTER and not being able to use a filter cursor in a further query. I again had one (in digits: 1) case of this becoming a problem because a query became fully optimzable with an added index :). But the awareness of it made me change habits, the awareness of mdots only when really of importance. Even considering what I said initially it's a thing with very low priority to change all code accordingly.

It's untrue, though, that we simply profit from all new hardware, VFP accelerates slower than other software, as it's only ever making use of one core. You only profit from more cores because other software (also VFP software) can use them and is no burden in concurrent usage. To make use of more cores there are some things, but the multithreading hack Calvin Hsia once showed in his blog, which lead to mtmyvfp is detected by data execution prevention (DEP) and may lead to putting your software into quarantine. The other option is Parallel Fox. Like the MTDLL option we always had it causes multiple runtimes to start and you can use it for a few things like sending out mails in a secondary background process, but you can't work on the same alias of the same datasession. Since nowadays the number of cores rather rises than the cpu frequency, you don't gain as much from the hardware development than up to about the year 2005. The biggest acceleration factors still are coming from using the best algorithm and caring about such details.

Last not least code not using mdot is vulnerable against attacks modifying tables to contain typical variable names. The expected result is errors and the benefit of that is getting at internal informations about the state of things in error logs and being able to do further hacks.

Errors are unavoidable parts of software development, you can minimize this error, but like compilable code is not guaranteed to work, so is mdotted code. The real problem are customers expecting error free software even in case they enter wrong data, while it would never occur to them to complain about the grammar and syntax errors in their text at the vendors of their pen or paper.

Bye, Olaf.
 
Dropped scatter / gather?
Never got that memo, use it everyday. But then, I don't use the buffering.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are not good for you.
 
That's OK if you're paid by the number of lines of code you write.[peace]

Many of us prefer to let the tool do what it does best and gain the competitive advantage of taking less time to get a job done. [wink]
 
And while I know I am crazy, I know I also remember this conversation/presentation in one of the sessions from DevCon in the past.

I'll just remark that some Devcon presenters said things that were, in a word, wrong.

Your mention of memory variables and naming conventions, though, rings a bell.

There was a statement in Alan Griver's first Codebook something like "using a naming convention for variables that is different than for fields can reduce the potential for confusion between the two", or words to that effect. It DID NOT say not to use the proper scoping where needed, although some people read it that way. It said that using different naming standards would diminish the danger of forgetting to use proper variable scoping
 
Griff, it's quite simple:

If you read in some data into variables via SCATTER and bind controls to them, some time after the user edited the variables you get at:
1. The edited value, which you can read from the variable
2. The current value reading table.field
and
3. You can cancel the modification by not GATHERing values back from variables to the table, selectively per field/variable, if you like.

With buffering:
1. You can read the edited value from table.field
2. You can read the current value of the dbf file with CURVAL(table.field)
3. You get the originally read in value with OLDVAL(table.field)
4. You can revert changes by TABLEREVERT for all buffered changes, a single row or even a single field and you can save by TABLEUPDATE, single or all rows.
5. You can check the automatically maintained states of all fields and the deleted field via GETFLDSTATE()
6. You can override them via SETFLDSTATE(). You might use this to not save some changes, for example.
7. You can use GETNEXTMODIFIED() to iterate all changed records beginning with lnModifedRecno = GETNEXTMODIFIED(0) and continuing lnModifedRecno = GETNEXTMODIFIED(lnModifedRecno) until lnModifedRecno becomes 0.
8. All that can be done with single row or table buffering, with automatic pessimistic or optimistic locking.
9. It also works with updatable views and cursoradapters.

I'm not so sure you can also use some of the function without turning on buffering, but even if so, the full advantages are only at your hand using it. Grab a little time and learn buffering, you don't have less control, you gain more control.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top