Jump to content
Macro Express Forums

check contents of a string variable


Recommended Posts

A text string array can contain items consisting only of letters, or of letters and digits, or of digits only. Example:

 

33e re 33e r BARLINE 33e 30q 8ts[[ 9ts 8]] BARLINE 6[ 8 30[ 33]] BARLINE 31[ 9] rq BARLINE 34e re 34e r BARLINE 34e 31q 9ts[[ 30ts 9]] BARLINE

 

Stepping through each text item of this array for evaluation is not the issue. The question is:

 

How can I quickly ascertain if an element contains number(s) only?

Or whether an element contains letters only (i.e. no special characters, such as "[" ).

Link to comment
Share on other sites

You could try to cast to an integer for the numeric check. But that seems inelegant. If it were me, I'd write a sub-macro that evaluates each character and returns a value representing the type that you can use to control your logic. 

Link to comment
Share on other sites

Hm... how would I evaluate each character and get it to return a value representing the type?

 

It seems like this shouldn’t be hard. I discovered that if I convert a string to an integer, for instance: "1cd" the integer returns "1", i.e. stripping out the letters. I could then check if the integer variable equals the text variable - where that is the case, I know that the text item contains only numbers...

 

As I am typing this it makes me wonder... as converting "1cd" to an integer yields "1" I then know that the string does not contain only digits. That’s fine as far as it goes. But it wouldn’t tell me, for instance, if the text string contains only letters. For instance, converting "0abc" and "abc" to an integer yields "0" in both cases. But one text string contains only letters, the other one also contains a zero.

Link to comment
Share on other sites

I can't think of a way to do it without checking every character.  It shouldn't be necessary to
compare every character to A, then to B, then to C, and so on -- you can reduce the number of IF
statements involved by looking for ranges.  For example,

 

Variable modify entire string to uppercase
Repeat for each character
    If character >= A
    and
    If character <= Z
    ...
    ...
    If character >= 0
    and
    If character <= 9
    ...
    ...
Repeat end

Link to comment
Share on other sites

Regarding checking for letters:  I see that you can change a string from lower- to upper-case and vise versa.  You could save copies of the sting, to var1 and var2, then make var1 UPPER and var2 lower and compare the two using the 'case-sensitive' option.   If they're the same--no letters.  ...wouldn't detect numbers or special characters though... 

Link to comment
Share on other sites

I was afraid there wouldn’t be a straightforward approach. Thanks for the tips. For now, I have coded as follows:

 

image.png.619c61ae7dfa91e3c7eefe88509517c8.png

 

The string variable I need to check is %pitchesAndRests[%counterPlusOne%]%. I convert it to an integer and then compare the integer to the string. If they are identical, then I know that the string item consists of digits only. Conversely, if they were not identical, I would know that there are other characters, but I would not know if there is a mixture of numbers and letters.

 

I know I could solve this in an "annoying" way... was just hopeful that some of the brilliant people here might have an ingenious solution that I can’t see...

 

Thanks again, everyone!

Link to comment
Share on other sites

Here is a way to check if a text string contains numbers. It tests whether the text string contains a zero, then a one, then a two... all the way to nine.

 

Variable Set String %x%: Prompt
 
Variable Set Integer %Digit% to 0
 
Repeat Until %Digit% Equals "9"
  If Variable %x% Contains "%Digit%"
    Text Box Display: "%x%" contains numbers
    Macro Stop
  End If
  Variable Modify Integer %Digit%: Increment
End Repeat
 
Text Box Display: "%x%" does NOT contains numbers

 

Link to comment
Share on other sites

4 hours ago, MakaPakaTobyHannah said:

convert it to an integer and then compare the integer to the string. If they are identical, then I know that the string item consists of digits only

 

For that to work, I think there is a limit to the size of the integer.  For example, the lines below always return "01234567899" in the Text Box Display, once the Set String exceeds 10 digits.  Comparing the string to the integer would not result in an equal condition. 

 

Variable Set String %T1% "0123456789987654321001234567899876543210012345678998765432100123456789987654321001234567899876543210"
Variable Modify String: Convert %T1% to integer %N1%
Text Box Display: %N1%

 

I think your best bet is the "annoying way" that Cory originally suggested.  if the ONLY special characters that can be there are "[" and "]", the job is simpler.  If ME had commands for inclusive OR, exclusive OR, and AND, for string variables of different lengths, it would also be simpler. 

 

But it's an interesting question.  I will keep trying to think of an ingenious solution.  🙂

Link to comment
Share on other sites

2 hours ago, acantor said:

I just tested my script with lengthy strings. It fails when the string is too long. But 500 characters seems to be OK.

 

It's odd your script would fail with long strings.  I tested it with a string over 400,000 bytes long, with digits near the very end.  (Though I ddin't use a Repeat loop, just hard-coded multiple IF CONTAINS statements.)  It took awhile to run, but worked fine.  Timeout of some sort, maybe? 

Link to comment
Share on other sites

7 hours ago, rberq said:

For that to work, I think there is a limit to the size of the integer.

 

That’s interesting to know; I will keep that in mind. Here, it’s a non issue, as there won’t be any strings containing more than two digits (by the way, this is music input code manipulation...)

 

acantor’s looping script may well be the most efficacious way of getting the information I need with respect to checking for the presence of digits. A positive result, however, only reveals that digits are present; it does not indicate whether there are digits only, or a mixture of digits and letters. I need to perform manipulations on those items of the array that contain only digits.

 

I really appreciate the constructive feedback! rberg, if that "ingenious solution" should pop into your head... I’ll be happy to find out about it. I dreamed of a solution to my code the other night. When I awoke, that solution was not re-constructible...  😉

 

Too bad one cannot construct a loop like acantor’s digit loop for all the letters of the alphabet (there is no secret "increment" way of cycling through all letters, is there?).

 

And more thinking out loud... perhaps, at the beginning, like "declarations," one could "hardwire" an array, with each consecutive item of the array assigned the next letter in the alphabet, like:

 

Variable Set String %checkIfLetter[1]% "a"

Variable Set String %checkIfLetter[2]% "b"

Variable Set String %checkIfLetter[3]% "c"

etc. etc. up to "z"

 

One could then cycle through the items in the array:

 

Variable Set String %x%: Prompt

 

Variable Set Integer %counter% to 1

 

Repeat Until %checkIfLetter[%counter%]% Equals "z"
  If Variable %x% Contains "%checkIfLetter[%counter%]%"
    Text Box Display: "%x%" contains letters
    Macro Stop
  End If
  Variable Modify Integer %counter%: Increment
End Repeat
 
Text Box Display: "%x%" does NOT contain letters

 

Just thinking...

 

 

 

Link to comment
Share on other sites

35 minutes ago, MakaPakaTobyHannah said:

Too bad one cannot construct a loop like acantor’s digit loop for all the letters of the alphabet (there is no secret "increment" way of cycling through all letters, is there?).

 

See my suggestion above.  Because the ASCII codes for all letters are grouped in a single range, you can code two IF statements instead of twenty-six.  I think that will work.   

 

    Variable Modify String (the one character you are examining) to upper case

    IF character greater than or equal to A
    AND
    IF character less than or equal to Z
    then it is alpha

    END IF

 

http://www.columbia.edu/kermit/ascii.html 
 

Link to comment
Share on other sites

That’s a good idea. One would have to know which character in the string to look for. The strings can have different numbers of characters (including letters and digits) occurring anywhere in the string. With the IF statement you constructed, one can examine only one character at a time; so you’d have to step through each character of the string in succession (with a procedure to determine when the end of the string is reached). That’s doable.

 

My approach is more of a brute force solution, but it permits examining the entire text string at once to see if anywhere in the string is any letter at all. So "9y3" would be identified immediately.

 

Thanks for all the good ideas!

Link to comment
Share on other sites

I wrote the good folks at Insight Software to ask about the upper limit of characters when assigning string variables.

 

Variable Set String %x%: Prompt

 

 

The upper limit is 6,832 characters (including spaces), at least when the characters are pasted into the field.

 

Variable Set String %Test% to "[very long string]"

 

I've tested this with strings of up to 1,000,000 characters long without problems.

 

Link to comment
Share on other sites

13 hours ago, acantor said:

I've tested this with strings of up to 1,000,000 characters long without problems.

The only problem I recall with long string variables, was saving them in Environment Variables.  I think I hit a problem at 8,192 bytes -- but I don't really remember for sure. 

Link to comment
Share on other sites

Oops, there was a logic flaw in my original script. It wasn't testing for the presence of 9!

 

I just tried this revised script with a string consisting of 1,200,000 characters, and it instantly reports if the string contains a digit or not.

 

Variable Set String %x% to "[insert your string here]"
Variable Set Integer %y% to the length of variable %x%
Text Box Display: The string contains %y% characters
 
Variable Set Integer %Digit% to 0
Repeat Until %Digit% Is Greater Than "9"
  If Variable %x% Contains "%Digit%"
    Text Box Display: YES, the string contains at least one digit
    Macro Stop
  Else
    Variable Modify Integer %Digit%: Increment
  End If
End Repeat
 
Text Box Display: NO, the string does not contain any digits

 

Link to comment
Share on other sites

Yeah, I saw your logic flaw but I didn't want to be obnoxious by pointing it out.  So I'm being obnoxious now, instead. 🙃

If your macro is scanning 1.2MB almost instantly, your PC must be faster than my 7-year-oldie.  Either that, or ME Pro maybe isn't doing the IF CONTAINS the same as ME 3.  

Link to comment
Share on other sites

My computer is about three years old, with a 4th Generation Intel Core i7 CPU. The latest CPUs are 9th Generation.

 

When opening the "set string" line to edit text consisting of hundreds of thousands of characters, I wait minutes! In fact, Macro Express freezes and becomes unresponsive. After two or three minutes, Macro Express rights itself.

 

I would be curious to know how long my code takes to run on your computer with, say, a string of 5000 characters.

Link to comment
Share on other sites

5 hours ago, acantor said:

I would be curious to know how long my code takes to run on your computer with, say, a string of 5000 characters.

 

My processor is Intel Core i3-2370M CPU @ 2.40GHz 2.40GHz.  I don't know what that means.  

 

Here's the ME routine I tested with.  I built a Notepad document so I could easily modify the number of characters for tests.
The first couple lines, copying to clipboard, took no more than a second or so, even with 500,000 characters.
Setting string T1 from the clipboard took many seconds, maybe 15 or 20 seconds, with 500,000 characters.  Very fast with only 5,000 characters.   

 

Displaying the "release" text box allows estimating the actual scan time (your code) -- that is, from the time I hit ENTER
to close the "release" box, until either the "contains" or "contains none" box appears.  

 

So, to finally answer your question, your code runs almost instantaneously whether I start with 5,000 characters or with 500,000.  I used Macro Return rather than Macro Stop like you did, but I doubt that matters much.  


//  
Text Type: <CTRLD>a<CTRLU>
Macro Run: 0_Generic_Copy_To_Clipboard
Variable Set String %T1% from Clipboard
Text Type: <END>
Text Box Display: release to start process
Variable Set Integer %N1% to 0
Repeat Until %N1% > 9
  If Variable %T1% contains "%N1%"
    Text Box Display: contains
    Macro Return
  Else
    Variable Modify Integer: Inc (%N1%)
  End If
Repeat End
Text Box Display: contains no digits
Macro Return
// 

  • Like 1
Link to comment
Share on other sites

Your approach gave me an idea of another way to handle the input data, but without using the clipboard. Create a plain text file that consists of one line. I used Notebook to create the file. I inserted a string of 600,000 characters on one line.

 

(PS: I typed 10 characters, selected everything and copied, and pasted ten times. Then I repeated the process until there are 1000 characters, then 10,000, then 100,000. It takes but a minute to generate hundreds of thousands, or millions, of characters.)

 

Then the script uses "Text File Begin Process." I specified the variable to receive the information, and chose "Process All Records" beginning on record 1.

 

It takes time to save the file, but once it has been saved, the macro runs almost instantly (at least on my computer).

Text File Begin Process: C:\Users\Me\Documents\tmptmp.txt
Text File End Process
Variable Set Integer %y% to the length of variable %x%
Text Box Display: %y%
 
Variable Set Integer %Digit% to 0
Repeat Until %Digit% Is Greater Than "9"
  If Variable %x% Contains "%Digit%"
    Text Box Display: YES, contains at least one digit
    Macro Stop
  Else
    Variable Modify Integer %Digit%: Increment
  End If
End Repeat
 
Text Box Display: NO, does not contain any digits

 

  • Like 1
Link to comment
Share on other sites

Yes, the time-consuming thing seems to be getting the data into a ME variable.  Scanning for "contains" is very fast.

You built your 600K test string about the same way I did.  So I guess I can't get you to hire me starting at one penny a day, if you will double my salary every day for a year. 

Link to comment
Share on other sites

 

4 hours ago, rberq said:

So I guess I can't get you to hire me starting at one penny a day, if you will double my salary every day for a year. 

 

When I was 13 years old, I participated in a 32 mile charity walk. Friends and family members pledged a penny or two or three per mile, but my Dad pledged one cent for Mile 1, two cents for Mile 2, four cents the Mile 3, etc.

 

After completing the walk, one of my friends (who was perhaps a bit more mathematically inclined than I was) realized something was amiss, and sat down at his desk in our Grade 7 class with pencil and paper. It took him about half and hour to work out that my Dad had committed to contributing $42,949,672.95 to charity!

 

My Dad wrote a cheque for $25, which was a lot of money in those days. A friend from a well-off family had pledged 5 cents per mile, and gave me $1.60!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...