5

Lets say I have a variable set to this:

set myVar to {"asdf", "qwerty24", "23", "22", "21abc" "20"}

How can I set a variable to the numbers in myVar, including those with text inside of the item--but without keeping the part that is text. Each item should only contain one number, if an item were to consist of multiple numbers ie "302 303" then the outputted result would preferably be just combined to "302303". Any spaces in the item need to be removed to, just like the text. If each number needs to be an integer so "0abc.1200" needs to have it's period removed and result with "1200". The result would be preferably listed as {"24", "23", "22", "21", "20"}, instead of being listed as {24, 23, 22, 21, 20}.

  • 1
    Could you give a more varied list of example items and, importantly, what you would expect the desired result to be ? For example, should "123abc456" map to {"123", "456"}, or just "123", or just "456", or "123456", or "123 456" ? One seemingly-simple item yields multiple possible solutions, and there's no way to know what one you deem "the correct" one. You need to be specific and try and cover all your scenarios, otherwise you won't get optimal solutions. You can edit the question to change/add information as needed. – CJK Jun 3 at 1:55
  • Okay I added some more information on what I want the result to be. The solution I want out of this is pretty broad so the it really doesn't matter what it maps to, as long as all text is removed from each item. – Adihsam Jun 3 at 7:42
  • 1
    That's a bit clearer. Another thing: you've been imprecise with your definition of what "text" is and what a "number" is. I think I know what you want, but for clarity: do you mean to say you want only digit characters retained in the text but the final items to remain as text, e.g. "23" (this is not a number; it is text that contains numerical characters, and forms a text representation of a number); and that you do not want the final items to be returned as numbers, e.g. 23. Summary: YES: {"24", "23", "22", "21", "20"}; NO: {24, 23, 22, 21, 20}. Correct? – CJK Jun 3 at 7:54
  • And... What about non-integer representations and leading or trailing zeroes? Should "0abc.12300" come back as "0.12300" or ".12300" or ".123" or "012300" or "12300"? – CJK Jun 3 at 8:01
  • There shouldn't be any numbers that aren't integers, but if a period appears before, after, or in between a number, it too should be removed. If there is a leading 0 it needs to go down to the number without it. so "0abc.12300" needs to be "12300" – Adihsam Jun 3 at 8:11
4

Objective: To process an AppleScript list of strings so that each string is filtered to remove any non-digit character followed by all leading zeroes. Resultant empty strings are discarded.

property digits : "0123456789"
property text item delimiters : {}


set L to {"abc", "qwerty.24", "01 abc23xyz", "123abc456", "2.1abc", "20"}

repeat with textItem in L
    set stringOfDigits to filterCharacters from textItem thru digits
    set numericalString to the processedNumericalString(stringOfDigits)

    set the contents of the textItem to the numericalString
end repeat

return the strings in L --> {"24", "123", "123456", "21", "20"}

------------------------------------------------------------------------------------------
# HANDLERS:
to filterCharacters from someText as text thru allowedCharacters as text
    local someText, allowedCharacters

    set tid to my text item delimiters -- to reset them after

    set my text item delimiters to {missing value} & characters in the allowedCharacters
    set illegalCharacters to characters of (text items of someText as text)

    set my text item delimiters to {missing value} & the illegalCharacters
    set filteredText to the text items of someText as text

    set my text item delimiters to tid
    return the filteredText
end filterCharacters


on processedNumericalString(numericalString as text)
    local numericalString

    if the numericalString = "" then return missing value

    try
        the numericalString as number
    on error
        the numericalString
    end try

    return the result as text
end processedNumericalString

Breakdown

property declarations

A property is similar to a variable, except for two differences: properties are persistent, and have global scope; variables are disposed of when a script ends, and default to local scope. I will let you research those terms if you need to, as it's beyond the remit of this answer. I almost never use a property for either of those features I just mentioned. Rather, I use them most often to separate storage of values that I generally intend to remain constant throughout the script (as opposed to variables that can be expected to change at any stage). AppleScript doesn't have a way to declare constants like other languages, so this is just a bastardisation of another construct.

Handlers

Handlers in AppleScript can be thought of to be what other languages refer to as a function, and the actual differences are nuanced and mostly academic, with one practical implication being that handlers aren't self-aware so can't report any information about themselves back to you. But, like functions, they receive arguments (or parameters), do something with them, and spit out a result at the end in most cases.

  • filterCharacters: this is the core of the script in terms of where the heavy lifting is done. It receives a single piece of text you wish to be filtered, and a list of allowed characters, and removes everything else, i.e. it extracts occurrences of allowed characters in the order they occur. It does this by utilising AppleScript's text item delimiters, which you should read about more thoroughly, but essentially deletes all instances of delimiters in the list you supply it, splitting the string into fragments at the points of deletion. So, it's almost performing the opposite function that we want, and can be thought of being a text filter that you supply a list of illegals rather than a list of allowables. Therefore, I use them twice: first to strip out the allowables, leaving only the illegals; then giving that list of illegals back to text item delimiters, which then get stripped from the original piece of text, thus leaving us only with allowables. Very efficient; avoids iterating through characters in the piece of text.

  • processedNumericalString(): This handler is just a cheap and lazy way to strip off the leading zeroes once the first handler has given us a string containing only digits. It would be arguably more correct to iterate through each digit character until reaching the first non-zero character, deleting the ones that are, with a special case to prevent "0" being obliterated. But, instead, I just decided to coerce the string to a number, then back to a string. A hack that works effectively and one assumes more speedily too (though that's not definitive).

The main body of the script

With the two handlers defined at the bottom of the script, all that remains is to iterate through the list of strings, sending each string in turn to each handler. What comes back is the piece of text you desire, which set the contents of... is what lets me replace the original item in the list with the new version. I was mindful not to retain empty strings (""), and the processedNumericalString() handler swaps those out for an AppleScript object called missing value that represents exactly what it says (it's the closest pre-defined AppleScript object to what other languages often call null or nil). Anyway, the important this is it isn't a string, because the final line of the script's run is:

return the strings in L

and this does exactly that: any item in the list that is not a string (or text) class of object is discarded. You can, of course, swap this line for:

set myVar to the strings in L

if you need it assigned to a variable in order to keep using it.


ADDENDUM

The OP added:

The list I described as myVar in the original post is always changing over time, I want the process of taking the items in myVar and isolating all the numbers to repeat indefinitely

OK. Let's bung the main part of the script into another handler:

to formNumericalStringsWithItems from L as list
    local L

    repeat with textItem in L
        set stringOfDigits to filterCharacters from textItem thru digits
        set numericalString to the processedNumericalString(stringOfDigits)

        set the contents of the textItem to the numericalString
    end repeat

    return the strings in L
end formNumericalStringsWithItems

Place this with the other handlers to keep it separate and out of the way now. The main body of the script is reduced to these two lines, where I've used the identifier myVar instead of L just for clarity:

set myVar to {"abc", "qwerty.24", "01 abc23xyz", "123abc456", "2.1abc", "20"}
set myNewAndImprovedVar to formNumericalStringsWithItems from myVar

Now, wherever myVar in your script gets updated/changed, you follow it with a call to this new handler, as I've illustrated here.

Just be clear about how I've delineated the different "parts" of the script: keep the property declarations at the top—don't put them inside your repeat loop; also don't put the handler declarations inside the repeat loop—I put all of mine at the bottom of the script, where I've marked a line and headed a section only for handlers. The "main body" of the script (despite now only being two lines here) is what your code will occupy, so keep things neat and grouped (it's why I separate the property declarations from the main body by two paragraph breaks instead of just one).

  • Will update answer with some explanation of what the script does. – CJK Jun 3 at 8:52
  • How can I make it so that this can repeat indefinitely? It is not allowing me to put this inside of a repeat cycle. – Adihsam Jun 3 at 9:40
  • I don't understand what you mean. Can you clarify what you want to do ? – CJK Jun 3 at 9:57
  • The list I described as "myVar" in the originally post is always changing over time, I want the process of taking the items in "myVar" and isolating all the numbers to repeat indefinitely. – Adihsam Jun 3 at 10:02
  • An important point you omitted in your post. Bear with me and I'll update the answer with an addendum. – CJK Jun 3 at 10:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .