Retaining decimal points in AppleScript when dealing with prices - applescript

I've got a huge text file with prices on each line embedded in a 15 character string.
Example:
185602008751285
In the example above the price is $2.00
I have no problem extracting the price. I am using the Satimage Scripting Addition
to add regular expression capability to AppleScript
and using the code:
set findPrice to find text "[0-9]{15}" in theString with regexp, string result and all occurrences
set findPrice2 to characters 5 thru 8 of item 1 of findPrice as string
set findPrice3 to findPrice2 * 0.01
The result of the code above is that I always get a number back with no
decimal places if the price is a whole number. But I need all prices to include
the cents (or a precision of 2).
How do I get AppleScript to output prices such as $2 to a format of $2.00 ?
Also, I can't round the prices so I can't use the round command.

There is a format_number routine here: http://www.j-schell.de/node/153 - this does more than you need, in that it will also insert thousands separators etc, but you can probably just use it "as is", or perhaps reduce it to just the decimal places functionality that you need. It also works with different locales etc.

Try this ...
set startPrices to quoted form of POSIX path of ("" & (path to desktop) & "prices.txt")
set endPrices to do shell script "grep -E [0-9]{15} " & startPrices & " | sed -e s'/^....\\(....\\)......./\\1/' -e s'/^0/$/' -e s'/^[0-9]/$&/' -e s'/..$/.&/'"

To keep from getting too long-winded, you can just manually put the decimal in there when getting the text pieces, or you can use printf to format your string (which would also get rid of leading zeros), e.g.
set findPrice to "185602008751285"
tell findPrice to set findPrice2 to text 5 thru 8
set findPrice3 to (do shell script "printf '%.2f' " & (findPrice2 * 0.01))

Related

If string does NOT contain and REGEX

I'm looking for a way to write the following javascript code in applescript: If the condition is false then I want to do something.
var regEx = /\d{5}/g;
var str = 'This string contains 12345';
if (!regEx.test(str)){
do something
}
Below is the applescript I started but it doesn't work.
set str to 'This string contains 12345'
set regEx to <NOT SURE HOW APPLESCRIPT HANDLES THIS>
if string does contains "12345" then
do something
end if
In Javascript ! = does not. What is the equivalent in applescript? and how do I handle RegEx?
My overall goal is to find out if the finder window selected DOES NOT contain any 5 digit number combination in the folder name.
tl;dr For any version of macOS that is >= OSX 10.8 you'll need to replace grep's -P option (as indicated in the "Solution" section below) with the -E option - as mentioned in the "Different grep utilities" section at the bottom of this post.
As correctly noted in the comments...
Vanilla AppleScript can't handle regex. - vadian
so you'll need to
shell out to something that does know regex - red_menace
Solution:
To meet your requirement with vanilla AppleScript in a way which is analogous to JavaScript's test() method, consider utilizing a custom AppleScript subroutine as follows:
Subroutine:
on regExpTest(str, re)
set statusCode to do shell script "grep -q -P " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
if statusCode is equal to "0" then
return true
else
return false
end if
end regExpTest
Usage:
set regExp to "\\d{5}"
set str to "This string contains 12345"
if regExpTest(str, regExp) then
display dialog "It DOES match so let's do something"
end if
Running the above script will display a dialog with the given message because there is a match between the regular expression and the specified string.
Note: AppleScript strings use the backslash as an escape character, so you'll notice that the \d metacharacter has been further escaped with an additional backslash, i.e. \\d
Inequality operators:
In Javascript != does not. What is the equivalent in applescript? and how do I handle RegEx?
AppleScript's inequality operators that are analogous to JavaScripts inequality operator (!=) are:
≠
is not
isn't
isn't equal [to]
is not equal [to]
doesn't equal
does not equal
So given your JavaScript if statement:
if (!regEx.test(str)){
// do something
}
We can achieve the same logic, (again using the aforementioned custom regExpTest subroutine), with the following code:
set regExp to "\\d{5}"
set str to "This string contains 1234"
if regExpTest(str, regExp) ≠ true then
display dialog "It DOES NOT match so let's do something"
end if
Note The str value only includes four consecutive digits, i.e. 1234.
This time running the above script will display a dialog with the given message because there is NOT a match between the regular expression and the specified string.
There are many variations that can be made to the aforementioned AppleScript if statement to acheieve the same desired logic. For example;
if regExpTest(str, regExp) is not equal to true then
...
end if
if regExpTest(str, regExp) = false then
...
end if
etc...
regExpTest subroutine explanation:
The aforementioned regExpTest AppleScript subroutine is essentially utilizing the do shell script command to run the following code that you would run directly via your macOS Terminal application. For instance in your Terminal application run the following two commands:
grep -q -P "\d{5}" <<<"This string contains 12345" 2>/dev/null; echo $?
Prints:
0
grep -q -P "\d{5}" <<<"This string contains 1234" 2>/dev/null; echo $?
Prints:
1
EDIT: Different grep utilities:
As noted in the comment by user3439894 it seems that some versions of the grep utility installed on Mac do not support the -P option which ensured the RegExp pattern was interpreted as a Perl regular expression. The reason why I opted to utilize a Perl Regular Expression is because they're more closely aligned to the regexp's used in JavaScript.
However, If you run man grep via your command line and discover that your greputility doesn't provide the -P option then change the following line of code in the regExpTest subroutine:
set statusCode to do shell script "grep -q -P " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
to this instead:
set statusCode to do shell script "grep -q -E " & quoted form of re & ¬
" <<<" & quoted form of str & " 2>/dev/null; echo $?"
Note: The -P option has been changed to -E so the pattern is now interpreted as an extended regular expression (ERE) instead.
The shorthand metacharacter \d
You may also find that you need to change the the assignment of the regexp pattern from:
set regExp to "\\d{5}"
to
set regExp to "[0-9]{5}"
This time the shorthand metacharacter \d, (which is used match a digit), has been replaced with the equivalent character class [0-9].
As others have said, you can use the Foundation framework’s NSRegularExpression via the AppleScript-ObjC bridge.
That said, Objective-C APIs, while powerful, aren’t exactly AppleScripter-friendly, so I knocked together some “standard libraries” a few years back that wrapped a lot of that general functionality as nice native AppleScript commands.
e.g. Here’s the nearest equivalent to your JavaScript using the Text library’s search text command:
use script "Text"
set str to "This string contains 12345"
set foundMatches to search text str for "\\d{5}" using pattern matching
if foundMatches is not {} then
-- do something
end if
Couldn’t drum up much interest so I no longer do development or support. But they’re free and open (public domain as far as I’m concerned) and still work fine in the current version of macOS AFAIK, so help yourself.

Bash Shell echo/printf how to format output the right way

My current snippet of code looks like this ...
#Location of network config files
nfds="/etc/sysconfig/network-scripts/"
#Standard prefer of network config files
fil="ifcfg-"
#Array variable that feeds "$nic"
cards= array loop built from "nic=$(ls /sys/class/net | grep en)"
#Set color for Divice labile
div="\033[38;5;39m"
#Set Fix format and colour info
fix="\033[38;5;118m"
#Set color for OK
ok="\033[38;5;28m"
#Clear All font and color info
ctf="\033[0m"
function currentCardDefRoute(){
defr=$(grep DEFROUTE $nfds$fil$cards | cut -d = -f 2)
if [[ $defr = "yes" ]] || [[ $defr = "no" ]]; then
echo -e " "$div$cards$ctf"'s current default route is\t"$div$defr$ctf"\t\t\t\t ["$ok"OK"$ctf"]"
$st
else
echo -e " "$div$cards$ctf"'s current default route is \t"$fix"Missing"$ctf"\t\t\t ["$fix"PLEASE FIX"$ctf"]"
$st
fi
}
I indent 1 space on all echo lines for readability and consistent formatting. Keeping output readable and easy to understand.
Im looking to us the "columns" option and make the output more dynamic and have the format consistent no matter the screen size or var result. I would love to also get rid of all the "\t"s in my code. I have tried printf to no success.
I googled a lot of different ways and not seen the specific answer Im looking for or a variation I can draw an answer from.
Thank you for your help.
btw. This is the first code I have ever written so go easy guys :)
You may want to try using the column utility. It's sole purpose is for formatting output into columns. That may be easier than trying to do the same thing with echo or printf.
If you have to use printf, you'll want to use a format specifier like "%25.25s". The first number is the "minimum field width", which (in this case) causes the output to be at least 25 characters wide. If the output is shorter, it's padded with whitespace. The second number indicates the maximum number of characters to print. When these two numbers are the same, it effectively says to print the string in a field that's exactly 25 characters wide. You can use this to force varying-length strings to take up the same amount of space on the screen.

How to allow variable tab length when calculating number of characters in a line

I'd like to calculate the number of characters in a line, but allow for the value of a tab character to change.
I've been working on a bash script that prints out the lines that have >80 characters (within the given files):
grep -r '.\{81,\}' $args
I guess I'm looking for a way to do something like this:
# pseudocode
TAB_LENGTH = 4
LINE_MAX = 80
if ( (number of non-tab characters) + TAB_LENGTH*(number of tab characters) > LINE_MAX)
print out the file, line number, and line.
fi
Any hints? (I'm quite new to bash scripting).
If you want to calculate for the number of characters in a line you would treat tab as a single character ('\t'). The width of a tab is set by the shell that you are using.
so you would just need
if ( (number of characters) > LINE_MAX)
print out the file, line number, and line.
fi
if you want to have control over fixed widths you can use printf to control the minimum field width for a given string.
printf "|%-5s|" "ABC"
which would have an output like this:
|ABC··|
(the · characters are placeholders for spaces in this example)
A very useful page for this can be found here (the syntax is for c++ but the explanations translate over to bash): http://wpollock.com/CPlus/PrintfRef.htm

Script to convert lower case characters into upper case is working differently as service action

I am trying a simple script as a service action in automator which performs this function:
Receives selected text in any application and replaces selected text
with the text containing capital letters
So I used this script:
on run {input, parameters}
set upperCaseString to ""
repeat with i in input
if (ASCII number i) > 96 and (ASCII number i) < 123 then
set upperCaseString to upperCaseString & (ASCII character ((ASCII number i) - 32))
else
set upperCaseString to upperCaseString & (ASCII character (ASCII number i))
end if
end repeat
return upperCaseString
end run
But I found this problem:
It was returning first letter of input as an upper case letter, eg.
input - lowercasetext, output - L, whereas the expected output was -
LOWERCASETEXT.
To check the problem I added this line of code in repeat loop:
display dialog i
and found that it is displaying complete text in place of single character at a time ,ie. in place of displaying l.. o.. w.. in lowercasetext it is displaying lowercasetext at once.
Can anyone suggest me why is it bugging me as service action while it is working fine in Apple Script Editor?
This works for a lot of languages:
on toUpper(s)
tell AppleScript to return do shell script "shopt -u xpg_echo; export LANG='" & user locale of (system info) & ".UTF-8'; echo " & quoted form of s & " | tr [:lower:] [:upper:]"
end toUpper
on toLower(s)
tell AppleScript to return do shell script "shopt -u xpg_echo; export LANG='" & user locale of (system info) & ".UTF-8'; echo " & quoted form of s & " | tr [:upper:] [:lower:]"
end toLower
When I run your script, I get the correct result. But one thing you may want to do is to explicitly coerce your result to text. The easiest way to do that would be at the end:
return upperCaseString as text
That may or may not do it for you, but you'll avoid a lot of frustration if you explicitly coerce data when there is a possibility of ambiguity.
Another (faster) way is to leverage the Unix tr (translate) command the via do shell script:
set upperCaseString to ¬
(do shell script ("echo " & input & " | tr a-z A-Z;"))
That's enough for 'English' language, but you can also add diacritical translation, like so
set upperCaseString to ¬
(do shell script ("echo " & input & " | tr a-zäáà A-ZÄÁÀ;"))
tr will translate anything to anything, so you can add any characters you may encounter and what you'd like them to translate to. A 'leet-speak' translator comes to mind.
You will get the same result in the AppleScript Editor if the input variable is set to a list. The input parameter of an Automator action is also a list, so your comparison isn't doing what you think. Note that text id's have obsoleted ASCII character and ASCII number commands - see the 10.5 AppleScript Release notes.
#Matt Strange:
You could also try:
set upperCaseString to ¬
do shell script "echo " & input & " | tr [:lower:] [:upper:]"
If you run 'man tr' on 'OS X 10.10' you may see that the character classes [:lower:] and [:upper:] should be used instead of explicit character ranges like 'a-z' or 'A-Z', since these may not produce correct results as it is explained there, on the manual page.

get language of currently logged in user via applescript

I want to get the system language of the currently logged in user. The line
set lang to do shell script "defaults read NSGlobalDomain AppleLanguages"
returns an string, which looks like
(
en,
de,
ja,
fr,
es,
it,
pt,
"pt-PT",
nl,
sv,
nb,
da,
fi,
ru,
pl,
"zh-Hans",
"zh-Hant",
ko,
ar,
cs,
hu,
tr
)
returns the users languages, but how can I get the first one of this 'array'? Is there a possibility to parse this as an array an get its first value?
There's a more direct method. Applescript has a command "system info" which returns a lot of useful information about the current user. Try this to see...
return system info
The information that will help you from that is "user locale". So you can get the language easily...
return user locale of (get system info)
Play around with this on different users and see if it gives you what you want.
The thread is really old, but I just had the problem and this comes up pretty high in a Google search. For other readers, I want to add two comments:
There is a difference between the “return user locale of (get system info)” and the “defaults read NSGlobalDomain AppleLanguages” strategies: The first returns the value from the region settings, the latter the value from the language settings (both in “Language & Text”).
Region settings return a language and a region, separated by underscore. Language settings return either just a language or language and region, separated by hyphen. If you use that in other code, make sure, it is tolerant.
The second point: GREPing works, but the simplest code I found is using the Property List suite from System Events:
on get_language()
set lang to do shell script "defaults read NSGlobalDomain AppleLanguages"
tell application "System Events"
set pl to make new property list item with properties {text:lang}
set r to value of pl
end tell
return item 1 of r
end get_language
grep my be faster, but this requires less brain twisting.
Jürgen
You can use awk and grep to prepare the list a little (get rid of indentation, quotes and parentheses), then split the resulting string:
-- a standard split function
to split of aString by sep
local aList, delims
tell AppleScript
set delims to text item delimiters
set text item delimiters to sep
set aList to text items of aString
set text item delimiters to delims
end tell
return aList
end split
-- pipe the output of defaults through a few more commands
set cmd to "defaults read NSGlobalDomain AppleLanguages | awk '{gsub(/[^a-zA-Z-]/,\"\");print}' | grep -v '^$'"
set langs to do shell script cmd
-- get the first item in the list
set lang to item 1 of (split of langs by return)
The shell command gives you a list like:
en
da
ja
fr
de
es
it
pt
pt-PT
nl
sv
nb
fi
ru
pl
zh-Hans
zh-Hant
ko
So item 1 will be en
By now this thread is ancient, but still the most relevant one of all results to my search entry. So I think this may be relevant to others searching for an answer to this question.
Based on what user1635960 wrote, the following “one liner” appears quite simple to me:
set lang to first word of (do shell script "defaults read NSGlobalDomain AppleLanguages")
As my first system language is German, it simply returns de.
Explanation:
do shell script "defaults read NSGlobalDomain AppleLanguages"
returns a list like
"(
\"de-DE\",
\"nl-DE\",
\"en-DE\"
)"
The class word defines a sequence of mainly letters and/or numbers, delimited by one or more of most other characters. So first word of the above list results in de.

Resources