Jump to content
Macro Express Forums

rberq

Members
  • Posts

    1,203
  • Joined

  • Last visited

  • Days Won

    61

Posts posted by rberq

  1. 1 hour ago, acantor said:

    Back to rberq's challenge: I added a timer to the script

    I did similar testing with a timer also.  Much of the run time was moving the clipboard data into a variable before starting the whole operation; so I started the timer AFTER that move was completed.  I found the same thing that you did -- all varieties of the script ran in about the same time, with one exception.  One of my versions, before the replace-2-with-1 loop, changed all strings of 30 spaces to 1 space, then all strings of 29 spaces to 1, then all 28, then 27, and so on.  When that was done, the loop usually had to run only once or twice and sometimes not at all.  That version ran significantly faster when the entire string was all or mostly-all spaces; but it ran significantly longer with mostly-character text.  

  2. If I understand the question, if the target "Page x of y" is always at the end, try this:

     

    move clipboard data to variable %work%,

    set integer %length% to length of %work%,

    set %position% to %length% minus 100,

    copy %work% from %position% for length of 100 to %shortwork%,

    use your existing logic to scan %shortwork% rather than scanning the whole PDF. 

     

    100 bytes pulled off the end of the file should be plenty, if the paging is always at the very end.  If not, use 200 bytes, or whatever.  The point is, scanning 100 bytes should be much quicker than scanning the whole PDF. 

     

    If you want to speed it up even more, don't search specifically for "of 50", "of 49", etc.  Rather, find the positions of "page " and "of ", then extract the next few characters beyond "of " and that should be the number of pages. 

  3. I/O error 103  The semaphore can not be set again.

    I got this error over and over last evening.  I'm surprised it hadn't happened before.  I was tinkering with a macro and made several changes to it, saving after each change.  Then I couldn't save any more, just got the above error message.    See attached screen shot -- the clue is at lower right in the system tray.  I don't know the exact mechanism, but the PC was uploading a very large file to Dropbox.  Meanwhile Dropbox apparently queued up the macro file to be uploaded, due to changes.  Eventually Dropbox must have put some kind of lock on the macro file, preventing more file changes.  Of course I panicked for a while, then made a guess that Dropbox was the problem.  Waited until the Dropbox synchronizing finished, then everything was OK. 

    macroexpress.jpg

  4. 3 hours ago, acantor said:

     

    I don't remember whether Macro Express 3 and 5 support Boolean variables.

     

    Yes, that naming convention certainly makes your macro more readable!

     

    I don't think ME 3 supports Boolean variables, as such.  My last job before I retired involved coding "medical logic modules" which were add-on customizations to a very large electronic patient care system in a hospital.  It used a scripting language that seemed to be halfway between BASIC and COBOL.  I liked its Boolean variables even better than what you are showing, because you didn't have to say IF ... EQUALS TRUE or IF ... EQUALS FALSE.  It was more like, FALSE was equivalent to null; and TRUE was equivalent to anything else.  

     

    So instead of
       Variable Set Bool %IsOrdinaryTextInClip% to "True"
       ...
       If Variable %IsOrdinaryTextInSelection% Equals "True"...

     

    you would both define the variable and set the condition by
       Clipboard_contains_ordinary_text = 1 (or = 7, or ="yes indeed it does", or any other value you felt like)  
          or
       Clipboard_contains_ordinary_text = "" (null)

     

    Then in the logic you would test the condition by
       If Clipboard_contains_ordinary_text ...
          or
       If not Clipboard_contains_ordinary_text ...

     

    This did away with the unnecessary verbiage of "equals true" and "equals false".  The variable was Boolean in the sense of having a value or being null; and the IF statement tested for existence or non-existence.  Of course you could also test for specific values, for example
       If Clipboard_contains_ordinary_text equals "yes indeed it does" ... 

     


     

  5. 1 hour ago, acantor said:

    the end of the universe is nigh!

    Great idea for a cartoon.  I wish I could draw. 

     

    First panel shows a man carrying the head end a long snake.  Another man behind him carrying more of the snake.

    Second panel two more men carrying more and more of the snake.

    Third panel two more men with more snake, but one of the men is carrying a sign that says, "The End is Near."

    Last panel a man carrying the tail end. 

     

    OK, I'll keep my day job.  Besides, somebody's probably done it already. 

    • Haha 1
  6. 1 hour ago, acantor said:

    Finally, a challenge within the challenge: I realize now that there is a way to reduce the number of lines of every example we have posted by one. What is that method? (Hint: It's not a particularly practical method so you might not use it in practice. But it does work.)

    I give up.  The only thing I can see is to eliminate the display of statistics at the end. 

  7. 3 hours ago, terrypin said:

    Those timings would obviously increase if I used a macro to apply the Replace command.

    Not necessarily.  My macro runs in about a second on a 91K file with not too many long space strings.  It runs in three seconds on a 335K file that is entirely spaces.  When the ME script runs, the hard work must be done by a pre-compiled routine within ME, so it's not necessarily slower than a RegEx command which likewise (I assume) uses pre-compiled logic. 

  8. 4 hours ago, acantor said:

    This might be the best way to meet rberq's requirement for a solution with the fewest lines of code. Only nine lines

     

    We can cut your nine lines down to eight, if we eliminate
    Variable Set String %b% to "%a%"
    and then do all operations on %a%.  That should help us finish before the universe either collapses or squirts through a black hole into somebody else's universe.  

     

    I tried all day to figure out how to use Terry's CRLF idea, just because I wanted so badly to use the Strip feature.  Couldn't come up with a reasonable way to deal with even-length space strings.

     

    I did find that my version runs considerably faster if I precede my Repeat loop with the following series -- but only if it's a VERY large string and contains VERY long strings of contiguous blanks.  I realize this takes me out of contention for the fewest-statements prize, but you've now got me worried about the cosmic deadline so I feel it's a worthwhile addition.

    // Initial removal of long space strings
    Replace "                              " with " " in %T1%
    Replace "                             " with " " in %T1%
    Replace "                            " with " " in %T1%
    Replace "                           " with " " in %T1%
    Replace "                          " with " " in %T1%
    Replace "                         " with " " in %T1%
    Replace "                        " with " " in %T1%
    Replace "                       " with " " in %T1%
    Replace "                      " with " " in %T1%
    Replace "                     " with " " in %T1%
    Replace "                    " with " " in %T1%
    Replace "                   " with " " in %T1%
    Replace "                  " with " " in %T1%
    Replace "                 " with " " in %T1%
    Replace "                " with " " in %T1%
    Replace "               " with " " in %T1%
    Replace "              " with " " in %T1%
    Replace "             " with " " in %T1%
    Replace "            " with " " in %T1%
    Replace "           " with " " in %T1%
    Replace "          " with " " in %T1%
    Replace "         " with " " in %T1%
    Replace "        " with " " in %T1%
    Replace "       " with " " in %T1%
    Replace "      " with " " in %T1%
    Replace "     " with " " in %T1%
    Replace "    " with " " in %T1%
    Replace "   " with " " in %T1%
    Replace "  " with " " in %T1%

     

    • Haha 1
  9. 4 hours ago, acantor said:

    I hope my fake logarithm calculator is right! It's been years since I have thought about logarithms!

    Yes, appears to be correct, and by calculating the minimum number of time you MUST go through the repeat loop, you very nicely minimize execution time. 

    Well .... not really minimize, because you will always loop enough times to handle the worst-case condition where the entire string, or most of it, consists of spaces.  Probably still faster than my version, which checks on every pass whether any double spaces still remain.  My version potentially saves passes through the "Replace" command, but at the expense of re-scanning the string each time to see if it's time to quit. 

  10. 15 hours ago, terrypin said:

    Too much else on my plate to spend serious time on it. But I’m wondering about another approach: replace all spaces with CRLF, then use one of the text processing loops to add a single space to the resultant ‘lines’.

    I'm thinking Terry has us both beat.  Should be a two-line macro:

    Replace all spaces with CRLF.

    Variable Modify String [Strip CR/LF].

     

    Bedtime now, but I'll try it tomorrow.

     

    strip.JPG

     

    EDIT: Well, so much for my midnight enthusiasm.  In the light of day, I can't see how it would work.

    The following would ALMOST work:

    1) Replace any existing CRLF by x'01'

    2) Replace all spaces by CRLF

    3) Strip all CRLF

    4) Restore original existing CRLF by replacing x'01' by CRLF

    But that would remove ALL spaces, and not leave one space where each string of spaces originally existed. 

    No prize yet, Terry, unless you can see your way out of this. 🙄

     

    EDIT AGAIN: Actually the above ALMOST works, if (step 2) all DOUBLE spaces are replaced by CRLF.  But some strings of spaces have an even number of spaces, and some have an odd number of spaces.  The above logic leaves odd-number strings with a single space, as desired.  But it completely removes even-number strings.  Have to find a way around that -- still thinking....  It runs pretty fast, though.  Have to go work in the garden.  I'll probably plant the flowers upside down if my mind is on this problem.

    • Haha 1
  11. 1 hour ago, acantor said:

    The "worst case" scenario is when the string consists entirely of spaces. The number of loops needed to strip away all of the extra spaces is, I believe, length - 1.

     

    Remember the story where Joe says, "I will work for you starting for penny a day, but you must double my pay every day."  So day 2, Joe earns 2 cents.  Day 3, 4 cents.  Day 4, 8 cents.  Then 16 cents, then 32, then 64, then $1.28, then $2.56.  Keep doubling, and in a few weeks Joe is very very wealthy.  The space-replacement works just the reverse: the total spaces are DIVIDED by 2 each time the macro says "replace every instance of space-space by space." 

     

    I created a text string of about 120K, entirely spaces, and here's the text box display at the finish of the macro:

       Beginning text length = 121311
       Ending text length      = 1
       Spaces removed         = 121310

       Number of loops         = 17

     

    2 to the power 17 is 132K.  So if my starting text string was more than 132K, there would be 18 loops.  To test, I doubled my text string, and voila:

       Beginning text length = 242622
       Ending text length       = 1
       Spaces removed         = 242621

       Number of loops         = 18

     

    If you DON'T use the "replace all instances" option of the ME command, then I believe the number of loops needed is (length - 1) as you suggest. 

     

     

    //  
    // Convert all multi-space strings to a single string -- starting with text in clipboard
    Variable Set String %T1% from Clipboard
    // Initialize counter for number of loops
    Variable Set Integer %N20% to 0
    // Save length of beginning text
    Variable Set Integer %N1% from Length of Variable %T1%
    // Repeat until there are no multi-space strings, then put the result back into the clipboard
    Repeat Until %N99% <> %N99%
      If Variable %T1% contains "  "
        Replace "  " with " " in %T1%
        Variable Modify Integer: Inc (%N20%)
      Else
        Repeat Exit
      End If
    Repeat End
    Variable Modify String: Save %T1% to Clipboard
    // Save length of ending text
    Variable Set Integer %N2% from Length of Variable %T1%
    // Display beginning and ending text lengths and number of spaces removed
    Variable Modify Integer: %N3% = %N1% - %N2%
    Text Box Display: Result
    //  
    Macro Return
    // 

     

     

  12. 1 hour ago, acantor said:

    Probably the way forward is to jettison the requirement for compactness, and add calculations to determine the maximum number of loops, which (I think) is a function of the length of the string. I'm not quite sure how to do that. I used to have reasonable mathematical intuitions, but it's been decades since I last studied the subject. My math skills have become rusty and my mathematical understanding is tenuous!

    I think maximum required loops depends on the length of the longest string of blanks, not the length of the entire string.  But by the time a macro did the counting, the brute-force method could be all done processing.  As you say, often the time penalty for brute force computing is trivial.  When I started programming, I worked with a guy who was immensely proud if he could cut a routine from, say, 44 to 42 bytes of machine-language code, to reduce run time.  The downside was, the next programmer to work with his stuff could spend hours or days trying to decipher his magic, because he also felt program logic was self-documenting and comments were for sissies.  🙂

  13. Your solution was almost identical to mine, except I put no limit on the number of loops.  Instead, I included an IF to see when to exit the loop.  Here are the "business" lines of code, without the housekeeping and displaying of counters:

     

    Repeat Until %N99% <> %N99%
      If Variable %T1% contains "  "
        Replace "  " with " " in %T1% (replace-all-instances option)
      Else
        Repeat Exit
      End If
    Repeat End

     

    With your macro, you can probably get away with far fewer passes than (length minus 1).  If you use the "replace all instances" option of the Replace command, then each time through the repeat loop cuts each space string roughly in half.  So the number of repeats needed is a power of 2 rather than based on overall string length.  For example, I made a string of about 78K bytes, whose longest contiguous string of spaces was about 41K.  It required only 16 iterations of the Replace command to do the job.  Which makes sense, because 2 to the 16th power is 64K.  

    Since my "challenge" specified a maximum of 2K contiguous spaces, your macro should be successful if you always repeated 11 times (maybe 12?) (2 to 11th power is 2K).  Knowing that, you could get rid of the lines that worry about overall string length, and you would beat me by a couple lines of code.  You win, pending any other entries.   

  14. 9 hours ago, acantor said:

    But here is a hint: the clarity of my solution comes less from the comments I added, and more from my naming convention with variables.

    Sounds like COBOL code (showing my age, here).  You can define a "conditional" value.  For example, you have a numeric data element called Programmer's-Age.  Then you define the conditional under it, like "88 the-programmer-is-a-dinosaur   values 65 to 100".  Within the program logic, then, you can say neat stuff like

    "if the-programmer-is-a-dinosaur

        goto eligible-for-social-security

            else

        goto standard-working-age." 

    When people say COBOL code is like reading English, it all comes from the naming. 

     

    Anyhow, the ability to use better naming is one thing that distinguishes ME Pro from my old ME 3 version.  I really would like to see your solution and your naming convention for this challenge, even though I'm too lazy to work on it myself. 

  15. 4 hours ago, acantor said:

    The goal is clarity!

    Clarity is largely a matter of EXTENSIVE commenting.  Complex macros or routines often will have almost as many remarks as functioning code.

     

    As to solving this, I have to say your Canadian Postal Code problem was fun and called for some cleverness.  This one appears to be mostly grunt work, not fun.🙄  I'd be delighted to do it for a hundred bucks an hour (US bucks, not Canadian -- hours can be measured on a US, Canadian, Slovakian, or 24-hour military clock).  But I can understand if you're not willing to pay that high since you've already written the code.🙃 

     

    Still eager for future challenges, though.  😛  In fact, here's one: Clipboard contains a piece of text with one or potentially many embedded strings of one or more blanks.  Total text can be up to 32K characters.  A string of contiguous blanks can be up to 2K in length.  Write a macro that changes every string of blanks to a single blank, without otherwise changing the overall text string.  At the end of the macro, display a count of how many blanks have been removed.  The challenge is to do this in the fewest lines of code.     

     

    Sorry, not trying to hijack your thread, I just don't want to work that hard tonight. 

  16. 10 minutes ago, acantor said:

    The letter "O" is used as a zero. (Presumably the opposite happens as well.)

    .

    I haven't thought this through all the way, but since the letter 'O' never occurs within a postal code, perhaps after upper-casing the address you could change every "O" to zero, then proceed as usual.  The danger would be possibly generating false positives elsewhere in the address, but as I suggested above, if there are two or more patterns that seem to be postal codes, most likely you would be safe accepting the last one. 

     

    I'm surprised you haven't also had the problem of people using a lower case "L" instead of the digit "1", or vice versa.  "L" is a legitimate code, so it wouldn't be amenable to the above "O" technique.  

  17. This solution builds the LDL DLD pattern by substituting characters:
    Any letter becomes @
    Any number becomes #
    Any space becomes $
    Then it searches for the pattern @#@$#@# within the substituted text, and extracts the corresponding positions from the original text.  The solution is a little crude because it doesn't allow for multiple pattern matches within the address -- probably I would add code to take the last match in that case.  

     

    Joe's solution using VBSCRIPT is certainly more elegant, but kind of breaks the ME-only rule.😧

     

    //  
    // Extract Canadian postal code
    Variable Set String %T1% "1234 Chaplin Dr. Twr. 1- 6th floor , Mississauga, ON L4Q 5Z3 Canada"
    Variable Set String %T1% "25 Clark Street, 1st Floor, Toronto, ON, M8C 1X9, Canada"
    Variable Set String %T1% "111 rue de Chaplain, Montreal PQ H2P 7W9"
    Variable Set String %T1% "J2E 6G2 (main entrance)"
    // Move address to working variable T2, clear destination variable T3
    Variable Set String %T3% ""
    Variable Modify String: Copy %T1% to %T2%
    Variable Modify String: Trim %T2%
    // Get rid of any special characters @, #, and $ that may already exist
    Replace "@" with "" in %T2%
    Replace "#" with "" in %T2%
    Replace "$" with "" in %T2%
    Text Box Display: Debug special characters removed
    // Replace letters with @, numbers with #, blank spaces with $, building result in T3
    Variable Set Integer %N1% to 0
    Variable Set Integer %N2% from Length of Variable %T2%
    Repeat Start (Repeat %N2% times)
      Variable Modify Integer: Inc (%N1%)
      Variable Modify String: Copy Part of %T2% to %T9%
      If Variable %T9% >= "A"
        AND
      If Variable %T9% <= "Z"
        Variable Set String %T9% "@"
      End If
      If Variable %T9% >= "a"
        AND
      If Variable %T9% <= "z"
        Variable Set String %T9% "@"
      End If
      If Variable %T9% >= "0"
        AND
      If Variable %T9% <= "9"
        Variable Set String %T9% "#"
      End If
      If Variable %T9% = " "
        Variable Set String %T9% "$"
      End If
      Variable Modify String: Append %T9% to %T3%
    Repeat End
    Text Box Display: Debug letters/numbers replaced with special characters
    // Postal code LDL DLD will have been replaced by @#@$#@#, so find position of that string within the address in variable T3
    Variable Set Integer %N9% from Position of Text in Variable %T3%
    // Extract corresponding characters from original [trimmed] address in T2
    Variable Modify String: Copy Part of %T2% to %T12%
    Text Box Display: Debug original address and extracted postal code
    //  
    //  
    Macro Return
    // 

  18. 5 hours ago, terrypin said:

    @mikecox

    After posting a query, in my experience you cannot rely on receiving a 'notification'. Just check back regularly.

    ...

    For responses, I have had good luck by clicking "Follow" at top-right, and selecting the option to get an email whenever there is activity.   Strangely enough, just because you originated a topic, doesn't mean you are automatically enrolled to "follow" it. 

    • Thanks 1
×
×
  • Create New...