Archive for the '内部計算(calc)' Category

2017/05/20 最大公約数を求めるv2

2つの数の最大公約数を求めるAppleScriptです。

素数チェックや素因数分解を作ったので、この手の計算を行ってみました。

AppleScript名:最大公約数を求めるv2
– Created 2017-05-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4653

set aRes to getGCDbetweenTwoNums(12, 18) of me
–> 6

–2つの数の最大公約数を求める
on getGCDbetweenTwoNums(aNum, bNum)
  set aRes to getPrimeFactor(aNum) of me
  
set bRes to getPrimeFactor(bNum) of me
  
  
–2つのリストを集合として扱い、積集合を求める
  
set aSet to current application’s NSMutableSet’s setWithArray:aRes
  
set bSet to current application’s NSMutableSet’s setWithArray:bRes
  
aSet’s intersectSet:bSet
  
set cRes to aSet’s allObjects() as list
  
  
set dRes to multipleListElements(cRes) of me
  
return dRes
end getGCDbetweenTwoNums

–与えられた数を素因数分解する
on getPrimeFactor(aTargNum)
  copy aTargNum to a
  
set pFactList to {}
  
  
repeat
    set pRes to checkPrimeNumber(a) of me
    
if pRes = true then
      set the end of pFactList to a
      
return pFactList
    end if
    
    
set aFactor to checkFactor(a) of me
    
set the end of pFactList to aFactor
    
set a to a div aFactor
  end repeat
end getPrimeFactor

–素数チェック
on checkPrimeNumber(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return false
    end if
  end repeat
  
return true
end checkPrimeNumber

–素因数チェック
on checkFactor(aNum)
  repeat with i from 2 to aNum - 1
    if aNum mod i is equal to 0 then
      return i
    end if
  end repeat
end checkFactor

–リスト内の要素をすべて乗算する
on multipleListElements(aList)
  set aNum to 1
  
set aRes to 1
  
repeat with i in aList
    set aRes to aRes * (aNum * i)
  end repeat
  
return aRes
end multipleListElements

★Click Here to Open This Script 

2017/05/18 16進数文字列を10進数数値に変換するv2

16進数文字列をCocoaの機能を利用して10進数数値に変換するAppleScriptです。

以前、Pure AppleScriptで組んだものがありましたが、ためしにCocoaの機能を利用して実行速度を比較してみました。

 Pure AppleScript版:0.03秒ぐらい
 本AppleScript:0.02秒ぐらい

Cocoaの機能を呼び出すAppleScriptObjCのScriptは、Pure AppleScriptにくらべて1回目の実行がやや遅くなるものの、同じ処理を複数回呼び出すと2回目以降の速度が大幅に上がる傾向があります。繰り返し実行する場合にはAppleScriptObjC版のほうがおすすめです。

AppleScript名:16進数文字列を10進数数値に変換するv2
– Created 2017-05-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4645

set aHex to “0×9AC”
set hNum to retIntFromHexString(aHex) of me

on retIntFromHexString(aHex as string)
  set {aRes, hexRes} to (current application’s NSScanner’s scannerWithString:aHex)’s scanHexInt:(reference)
  
if aRes = false then
    return “” –エラーの場合
  else
    return hexRes
  end if
end retIntFromHexString

★Click Here to Open This Script 

2016/10/28 ベクトルのコサイン類似度を計算する v2

ベクトル同士のコサイン類似度を計算するAppleScriptの改良版です。

「ガンダム」「アムロ・レイ」「ガンキャノン」

という3つの言葉の類似度を計算したところ、

 (1)「ガンダムとガンキャノン」
 (2)「アムロ・レイとガンキャノン」
 (3)「アムロ・レイとガンダム」

の順に類似度が計算されてしまい、「ガンキャノン問題」として問題視されました。

Apitoreさんより「ベクトルの長さで正規化するとよい」という助言をいただき、いろいろ調べて改良してみたものです。

その結果、

 (1)「ガンダムとガンキャノン」
 (2)「ガンダムとアムロ・レイ」
 (3)「アムロ・レイとガンキャノン」

の順番に計算結果が出るようになり、一安心しています。

AppleScript名:ベクトルのコサイン類似度を計算する v2
– Created 2016-10-28 by Takaaki Naganoya
– 2016 Piyomaru Software
–以下のページを参照しました
–http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html
–http://piyocast.com/as/archives/4293

set aRec to {startTime:“1477635439753″, |word|:“ガンダム”, endTime:“1477635439754″, |log|:“Success.”, |vector|:{-0.173511996865, 0.186350002885, 0.288884997368, 0.107758000493, 0.287292987108, 0.119222998619, 0.246404007077, -0.332718014717, -0.309754997492, 0.326180011034, 0.499563008547, -0.131274998188, 0.238587006927, -0.317025989294, -0.008682000451, 0.619518995285, 0.316774994135, -0.053045999259, 0.028408000246, -0.428086012602, -0.607270002365, 0.657006978989, 0.676119029522, 0.203107997775, -0.316679000854, 0.082666002214, -0.310041993856, 0.603790998459, 0.468154996634, 0.206021994352, 0.028333999217, -0.087867997587, -0.358617991209, 0.128415003419, 0.037046000361, -0.260360985994, -0.210915997624, -0.015564999543, -0.180935993791, 0.083250999451, -0.193316996098, 0.250761002302, 0.202393993735, -0.155086994171, 0.036905001849, 0.418110996485, 0.067231997848, -0.116421997547, -0.341655999422, 0.05919200182, 0.389017999172, -0.544457018375, -0.244222998619, 0.337971001863, 0.163227006793, 0.117914997041, -0.042672999203, -0.215838998556, 0.191798001528, 0.174465000629, -0.055527999997, 0.121985003352, -0.046782001853, -0.347003012896, -0.425747990608, 0.576622009277, 0.322551995516, -0.426732987165, -0.580038011074, -0.579939007759, 0.29191800952, 0.076993003488, 0.220890000463, -0.374727010727, 0.11546599865, 0.239750996232, -0.599394023418, 0.581852018833, -0.124090999365, -0.180638998747, 0.5446190238, -0.65235298872, 0.456075012684, 0.494884997606, 0.484183996916, 0.020594999194, 0.362075001001, -0.089720003307, 0.230300992727, 0.281304001808, 0.286731004715, 0.374053001404, -0.177623003721, 0.090945996344, -0.399394005537, 0.573561012745, 0.130366995931, 0.15235799551, -0.323183000088, 0.143162995577, 0.274109989405, 0.520829021931, 0.171061992645, -0.079223997891, -0.529187977314, 0.109682999551, -0.433328002691, -0.26163700223, -0.624193012714, 1.016695022583, -0.359939008951, 0.183194994926, 0.018155999482, -0.14149799943, -0.240256994963, 0.413583993912, 0.378069013357, -0.35772100091, 0.056784998626, 0.842347025871, -0.041281998158, 0.121949002147, -0.55557101965, -0.012947999872, -0.451754003763, 0.095089003444, 0.468187004328, -0.376350998878, 0.78152102232, 0.307211011648, -0.709493994713, -0.498080998659, -0.324746012688, -0.199910998344, 0.066499002278, -0.047377999872, -0.116584002972, -0.392536014318, 0.534222006798, -0.004480999894, 0.106450997293, 0.492370009422, -0.205549001694, -0.138926997781, -0.25551199913, 0.122440002859, -0.063225999475, 0.400667995214, -0.294638991356, -0.618892014027, -0.163193002343, -0.203306004405, -0.500850975513, 0.183540001512, -0.46670499444, -0.213167995214, -0.276264995337, 0.204497992992, -0.156630992889, 0.383563011885, 0.496547013521, 0.113885998726, 0.020508000627, -0.389571994543, 0.218575999141, -0.064272001386, -0.026503000408, -0.173591002822, 0.254842013121, 0.464908987284, -0.103918999434, -0.269497007132, 0.070835001767, 0.203738003969, 0.181133002043, -0.246653005481, -0.136351004243, -0.24780100584, 0.326480001211, -0.193390995264, -0.041266001761, 0.245121002197, -0.118851996958, -0.083679996431, -0.171301007271, 0.031709998846, -0.332567989826, -0.059787001461, 0.001627000049, -0.048179998994, -0.396964997053, 0.31639200449, -0.352144986391, 0.008798000403, -0.232255995274, -0.394028007984, 0.116296000779, 0.171626001596, 0.013128999621, -0.295181006193}, processTime:“1″}

set bRec to {startTime:“1477635460487″, |word|:“アムロ・レイ”, endTime:“1477635460487″, |log|:“Success.”, |vector|:{0.03407099843, 0.10659699887, 0.127606004477, -0.13093200326, 0.17143599689, -0.386317998171, 0.223474994302, -0.63797801733, -0.21521499753, 0.215176001191, 0.607864022255, 0.176204994321, -0.184221997857, 0.361393988132, 0.16435199976, 0.652567028999, 0.242174997926, -0.325437992811, 0.394699007273, -0.393142998219, -0.312689989805, 0.173059001565, 0.660327970982, -0.07935500145, -0.34789198637, -0.223361998796, -0.153245002031, 0.175822004676, 0.104438997805, 0.50031298399, 0.16487300396, -0.138288006186, -0.054469998926, 0.100807003677, 0.05673699826, -0.067408002913, 0.017626000568, -0.07518299669, -0.201003998518, -0.005166999996, -0.088767997921, 0.615378975868, 0.126588001847, -0.127129003406, 0.159886002541, 0.374316006899, -0.03769300133, -0.050262000412, 0.063642002642, 0.169852003455, 0.409768998623, -0.453413009644, -0.122203998268, 0.294649988413, 0.11619400233, 0.576021015644, -0.117141999304, -0.486111998558, 0.283957004547, -0.101135000587, -0.078950002789, 0.173895001411, -0.083311997354, 0.028666999191, -0.21795900166, 0.184988006949, -0.185552999377, -0.399181008339, -0.098324000835, -0.352382987738, 0.075119003654, -0.17525100708, 0.373353004456, -0.152073994279, 0.051049001515, 0.110192000866, -0.726333022118, 0.334517002106, -0.075718998909, -0.354999989271, 0.655991971493, -0.298009991646, 0.508288025856, 0.243245005608, 0.239094004035, -0.086781002581, -0.161684006453, -0.507776021957, 0.261065006256, 0.284135997295, 0.307931989431, 0.213102996349, 0.136901006103, 0.397157996893, -0.464179992676, 0.262387990952, 0.380863010883, -0.071410998702, -0.165156006813, 0.135739997029, 0.283789008856, 0.820464015007, -0.359337002039, 0.155907005072, -0.330406993628, 0.400182008743, 0.119069002569, -0.182172998786, -0.147823005915, 0.674717009068, -0.637548983097, -0.110163003206, 0.025941999629, -0.274792999029, -0.184186995029, 0.543650984764, 0.189351007342, -0.354799985886, -0.005100999959, 0.318190008402, 0.088809996843, 0.300523996353, -0.336024999619, -0.279132008553, -0.489708006382, 0.119197003543, 0.357654988766, -0.009196000174, 0.908367991447, 0.127497002482, -0.877427995205, -0.362311005592, 0.045292001218, 0.228176996112, 0.003637999995, -0.021867999807, 0.264483004808, -0.531185984612, 0.075176000595, -0.258029013872, 0.180007994175, 0.549230992794, 0.085698001087, 0.164148002863, 0.198268994689, 0.206103995442, 0.182986006141, 0.262667000294, -0.509878993034, -0.44718798995, 0.136090993881, -0.18127900362, -0.148757994175, 0.263893991709, -0.386029988527, -0.198642000556, 0.220932006836, 0.202956005931, 0.048569001257, 0.194492995739, 0.180389001966, 0.697315990925, 0.139156997204, -0.228732004762, 0.201507002115, -0.043519001454, -0.419701009989, -0.424322992563, 0.085637003183, 0.513258993626, -0.90073800087, -0.365974009037, -0.043921001256, -0.012201000005, 0.343672990799, -0.352656006813, 0.335415005684, -0.584758996964, -0.045765001327, -0.614067018032, 0.095513001084, 0.461355000734, -0.371479004622, -0.612700998783, 0.043907001615, 0.56964302063, -0.364234000444, -0.080641999841, 0.140410006046, -0.180212005973, -0.543507993221, 0.225119993091, -0.285872995853, 0.08812700212, -0.299535006285, 0.026107000187, -0.221154004335, 0.39902600646, 0.160721004009, -0.433041006327}, processTime:“0″}

set cRec to {startTime:“1477635477524″, |word|:“ガンキャノン”, endTime:“1477635477524″, |log|:“Success.”, |vector|:{0.072226002812, -0.123470000923, 0.229124993086, 0.024253999814, 0.090787000954, -0.554116010666, 0.127351999283, -0.277144014835, -0.273193985224, 0.049963001162, 0.459771990776, -0.271524995565, 0.12961499393, -0.174656003714, 0.56355202198, 0.922071993351, 0.629299998283, 0.046698000282, 0.017914000899, -0.093442000449, -0.435452997684, 0.599241018295, 0.600166976452, -0.085536003113, -0.361353993416, 0.147931993008, -0.145070001483, 0.277393013239, 0.016388999298, 0.262728989124, 0.212905004621, 0.189909994602, -0.292201012373, 0.332486003637, 0.308021992445, -0.036079999059, -0.271553009748, -0.20025600493, -0.090479001403, 0.268270999193, -0.272096991539, 0.199298992753, 0.15323600173, -0.348919987679, 0.290313988924, 0.180563002825, -0.179280996323, -0.239015996456, -0.279372006655, 0.237440004945, 0.588576972485, -0.73378098011, -0.176648005843, 0.382687985897, 0.023191999644, 0.218005001545, 0.104557998478, -0.209011003375, -0.139624997973, 0.429735004902, 0.027498999611, -0.114556998014, 0.439689993858, -0.343279987574, -0.206854000688, 0.510254979134, 0.38624098897, -0.413646996021, -0.354449987411, -0.344117999077, -0.059645000845, 0.084478996694, 0.013961999677, -0.162633001804, 0.16069200635, -0.239609003067, -0.710308015347, 0.490334004164, 0.209011003375, -0.068875998259, 0.620296001434, -0.67517799139, 0.308690011501, 0.349496990442, 0.543331027031, 0.014736999758, 0.265686988831, -0.242991000414, 0.08111499995, 0.433555006981, 0.534663021564, 0.440093994141, 0.046149998903, 0.456764996052, -0.426779985428, 1.205618023872, 0.433625012636, 0.19698600471, -0.024245999753, -0.195654004812, 0.778258979321, 1.02594602108, -0.0279610008, -0.08894199878, -0.757061004639, 0.001425000024, -0.355924993753, 0.055286001414, 0.080266997218, 0.389950990677, -0.39531698823, 0.532419979572, 0.106784999371, -0.050149999559, -0.230510994792, 0.41841301322, 0.785488009453, 0.17853499949, 0.012822999619, 0.533285975456, 0.046064998955, 0.457116991282, -0.336412996054, 0.086345002055, -0.490134000778, -0.060506001115, 0.505389988422, -0.440815001726, 0.701705992222, 0.233691006899, -0.556469976902, -0.175993993878, 0.047694001347, -0.439999997616, 0.048073999584, 0.32014799118, -0.157723993063, -0.406812012196, -0.235781997442, 0.149423003197, 0.221878007054, 0.274697005749, -0.336528003216, -0.027574999258, -0.05121299997, 0.049157001078, -0.061744999141, 0.571139991283, -0.426824986935, -0.511521995068, -0.180418998003, -0.173777997494, -0.501815021038, 0.165115997195, -0.52134001255, -0.110209003091, -0.296977996826, 0.113278999925, -0.254267007113, 0.274937003851, 0.171541005373, 0.226473003626, -0.05610800162, -0.063437998295, 0.179731994867, 0.016723999754, -0.181597992778, -0.0923660025, 0.297807008028, 0.402370989323, -0.933079004288, -0.062503002584, 0.156483992934, 0.066535003483, -0.129124999046, -0.464343994856, 0.046394001693, -0.510720014572, 0.117109999061, -0.378863990307, 0.104653000832, 0.297672003508, 0.057688999921, -0.290758013725, -0.042853001505, 0.69950902462, -0.666705012321, -0.062345001847, 0.131890997291, 0.12205799669, 0.190595000982, 0.141661003232, -0.141069993377, 0.29548099637, -0.252436995506, -0.12503400445, 0.245934993029, 0.292874008417, -0.207329005003, -0.592303991318}, processTime:“0″}

set aList to |vector| of aRec
set bList to |vector| of bRec
set cList to |vector| of cRec

set aRes to calcCosinSimilarity(aList, bList) of me –ガンダムとアムロ・レイ
set bRes to calcCosinSimilarity(aList, cList) of me –ガンダムとガンキャノン
set cRes to calcCosinSimilarity(bList, cList) of me –アムロ・レイとガンキャノン

return {aRes, bRes, cRes}
–> {44.057800255168, 50.555325012947, 32.83911534787}
–(1)「ガンダムとガンキャノン」、(2)「ガンダムとアムロ・レイ」、(3)「アムロ・レイとガンキャノン」の順番

–コサイン類似度をベクターのリストから計算する
on calcCosinSimilarity(aList, bList)
  set aLen to length of aList
  
set bLen to length of bList
  
if aLenbLen then error “Not Same Item Nums”
  
  
set aRes to 0
  
repeat with i from 1 to aLen
    set a1 to (contents of item i of aList)
    
set b1 to (contents of item i of bList)
    
    
set vL to getVectorLength(a1, b1) of me
    
set normF to (1 / vL)
    
set aRes to aRes + ((a1 * normF) * (b1 * normF))
  end repeat
  
  
return aRes
end calcCosinSimilarity

–ベクトルの長さを求める
on getVectorLength(a, b)
  return getSQR(a ^ 2 + b ^ 2) of me
end getVectorLength

–平方根を求める
on getSQR(aNum)
  return (aNum ^ 0.5)
end getSQR

★Click Here to Open This Script 

2015/03/03 2点間の距離を求める

This AppleScript calculates the distance (km) between 2 places. Place data is a pair of Latitude and Longitude.

This Script requires ASObjCExtras Framework.

dist.png

2点間の距離を求めるAppleScriptです(単位:km)。位置情報は緯度と経度のペアで与えます。実行には、ASObjCExtras Frameworkのインストールが必要です。

AppleScript名:Calc Distance between 2 places v2
– Created 2015-03-03 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ASObjCExtras"

set aPlace to {latitude:35.737072, longitude:139.637826} –Seibu-Ikebukuro Line Nakamurabashi Station (My Nearest Station)
set bPlace to {latitude:35.753108, longitude:139.595123} –Amusium OSC (Game Center, Nearest Senjo-No-Kizuna POD)

set aDistance to calcDistanceBetweenPlaces(aPlace, bPlace)
–>  4.251157707731 (km)

–2点間の距離を計測する(km単位)
–参考:http://log.nissuk.info/2012/04/2.html
on calcDistanceBetweenPlaces(aPlace, bPlace)
  
  
set r to 6378.137 –Equatorial radius/赤道半径(km)
  
  
–Place A
  
set lat1 to (latitude of aPlace) * pi / 180
  
set lng1 to (longitude of aPlace) * pi / 180
  
  
–Place B
  
set lat2 to (latitude of bPlace) * pi / 180
  
set lng2 to (longitude of bPlace) * pi / 180
  
  
–Calculation
  
set calc1 to (current application’s SMSFord’s sinValueOf:lat1) as real
  
set calc2 to (current application’s SMSFord’s sinValueOf:lat2) as real
  
  
set calc3 to (current application’s SMSFord’s cosValueOf:lat1) as real
  
set calc4 to (current application’s SMSFord’s cosValueOf:lat2) as real
  
  
set calc5 to (current application’s SMSFord’s cosValueOf:(lng2 - lng1)) as real
  
  
set aDist to (current application’s SMSFord’s acosValueOf:(calc1 * calc2 + calc3 * calc4 * calc5)) as real
  
set aDist to aDist * r
  
  
return aDist
  
end calcDistanceBetweenPlaces

★Click Here to Open This Script 

2014/11/04 レコードをリストから生成(ASOC)

リストでラベルとデータを与えると、レコードを生成するAppleScriptです。

これまで、Script Editor上で記述するAppleScriptでは、言語仕様に「レコードを動的に生成する」という機能が盛り込まれていなかったため、かなり無理矢理に実現してきた機能です。

力技の歴史をみると、

(1)run scriptで強引にAppleScriptそのものを生成してファイルに書き出して読む

(2)run scriptで強引にAppleScriptそのものを生成してそのまま受け取る

とだんだん洗練されてきたところに、

(3)Cocoaの機能を呼び出して生成する

という新たな段階に達した、ということでしょうか。(1)が登場したときにもじゅうぶんに画期的な技術であったのですが、これだけScripterが必要としている機能が言語仕様に持ち込まれてこなかった、というのも驚きです。

AppleScript名:asoc_レコードをリストから生成
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set labelList to {“Address”, “Names”}
set valueList to {“ここらへん”, “ぴよまるさん”}

set theResult to current application’s NSDictionary’s dictionaryWithObjects:(valueList) forKeys:(labelList)
set aRec to theResult as record

–> {Address:”ここらへん”, Names:”ぴよまるさん”}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/29 変数に入っているデータの「型」を求める

変数の中に入っているデータの「型」を求めるAppleScriptです。

  class of 変数

で求められます。

スクリプト名:変数に入っているデータの「型」を求める
set a to 1
class of a
–> integer

set b to 1.0
class of b
–> real

set c to "1"
class of c
–> text

set d to selection of application "Finder"
class of d
–> list

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/04/26 JANコードのチェックデジットの計算

JANコードのチェックサムを計算するAppleScriptです。

バーコードに使われている「JANコード」は13桁から構成されるコードであり、うち最初の12桁がデータで、最後の1桁はチェックサムです。

barcode.jpg

このチェックサムを計算するという、割とどうでもいいような感じのするものを手元にストックしていなかったので、やはりかなりどうでもいいような気もするものの、作っておきました。

スクリプト名:JANコードのチェックデジットの計算
set aData to “240469540245″ –女性用カジュアルパンプス(黒)
set aSum to calcJANcodeChkSum(aData)
–> 9

set aData to “978479731648″ –「Mac使いへの道」
set aSum to calcJANcodeChkSum(aData)
–> 3

–JANコードのチェックデジットの計算
–参照元:http://www.kabukoba.co.jp/info/barcode/check.htm
on calcJANcodeChkSum(aData)
  set aList to characters of aData
  
  
if length of aList is not equal to 12 then return false
  
  
set kiSnum to 0
  
set guNum to 0
  
  
repeat with i from 2 to length of aList
    
    
set kiSuF to ((i - 1) mod 2)
    
    
set j to (item i of aList) as number
    
    
if kiSuF = 1 then
      –奇数
      
set kiSnum to kiSnum + j
    else
      –偶数
      
set guNum to guNum + j
    end if
    
  end repeat
  
  
set kiSnum to kiSnum * 3
  
set guNum to guNum + (first item of aList) as number
  
  
set totalNum to kiSnum + guNum
  
  
set totalChar to totalNum as string
  
set lastDig to (last character of totalChar) as number
  
if lastDig is not equal to 0 then
    set sumNum to 10 - lastDig
  else
    set sumNum to 0
  end if
  
  
return sumNum
  
end calcJANcodeChkSum

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/06/19 指定フォルダが所属するDiskの空き容量を取得する

指定フォルダが所属するDiskの空き容量を取得するAppleScriptです。

USBメモリ上のフォルダを指定したら、そのUSBメモリの空き容量を求めます。

サーバー上のQuotaがかかった(ユーザーごとの書き込み上限容量が設定された)状態の使用可能残容量を求めるといった用途は考慮していません。

スクリプト名:指定フォルダが所属するDiskの空き容量を取得する
set aFol to choose folder

set fRes to getFreeSpace(aFol) of me

on getFreeSpace(aFol)
  set aFolStr to aFol as string
  
set aList to parseByDelim(aFolStr, “:”) of me
  
set aDiskName to contents of first item of aList
  
  
tell application “Finder”
    set aDisk to disk aDiskName
    
set aFree to free space of aDisk
  end tell
  
  
set numberString to Stringify(aFree) of me
  
  
return numberString
  
end getFreeSpace

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–数字の文字だけが入っているかどうかをテストする
–数字の文字のみから構成されていたらtrue、1文字でもそれ以外のものが入っていたらfalse
on detectContainsOnlyNumChar(testText)
  –Numeric文字列(大文字小文字は問わない)
  
set ankChar to {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”, “-”}
  
  
set _testChar to testText as Unicode text
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is not in ankChar then
        return false
      end if
    end repeat
  end ignoring
  
  
return true
end detectContainsOnlyNumChar

–指数表示数値を文字列化
on Stringify(x) – for E+ numbers
  set x to x as string
  
set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {“E+”}}
  
if (count (text items of x)) = 1 then
    set AppleScript’s text item delimiters to {tids}
    
return x
  else
    set {n, z} to {text item 1 of x, (text item 2 of x) as integer}
    
set AppleScript’s text item delimiters to {tids}
    
set i to character 1 of n
    
set decSepChar to character 2 of n – “.” or “,”
    
set d to text 3 thru -1 of n
    
set l to count d
    
if l > z then
      return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d))
    else
      repeat (z - l) times
        set d to d & “0″
      end repeat
      
return (i & d)
    end if
  end if
end Stringify

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/06/19 SI接頭辞つきの数値を具体的な数値の文字列に評価して返す

“M”とか”G”とかの単位を表す文字を末尾に指定した数値表現を、具体的な数字に評価して(文字列で)返すAppleScriptです。基数を1000もしくは1024で指定できます。

「ディスクの空き容量が40GB以下だったら処理しない」といった指定ができるように、作ってみました。

AppleScriptの処理系自体は、10E10ぐらいで指数表示になってしまい、大きな数値を扱うのにあまり向いていませんが……このように数値を文字として保持し、計算はbcコマンドを用いれば巨大な数値を扱えるようになります。

……いかにも、世界のどこかで誰かが作っていそうな感じではありますが(逆の働きをするものは自分でも作っていました)、すぐには見つからなかったので、仕方なく。

スクリプト名:SI接頭辞つきの数値を具体的な数値の文字列に評価して返す
set aRes to procMetricPrefix(“4K”, 1024) of me
–> “4096″

set aRes to procMetricPrefix(“4M”, 1024) of me
–> “4194304″

set aRes to procMetricPrefix(“4G”, 1024) of me
–> “4294967296″

set aRes to procMetricPrefix(“4G”, 1000) of me
–> “4000000000″

–SI接頭辞つきの数値を具体的な数値の文字列に評価して返す
–https://en.wikipedia.org/wiki/Metric_prefix
on procMetricPrefix(numStrWithMetric, aBase)
  
  
if (aBase = 1024) or (aBase = 1000) then
    
    
set numPart to (text 1 thru -2 of numStrWithMetric) as integer
    
set aBaseStr to aBase as string
    
    
if numStrWithMetric ends with “K” then
      set multNum to 1
    else if numStrWithMetric ends with “M” then
      set multNum to 2
    else if numStrWithMetric ends with “G” then
      set multNum to 3
    else if numStrWithMetric ends with “T” then
      set multNum to 4
    else if numStrWithMetric ends with “P” then
      set multNum to 5
    else if numStrWithMetric ends with “E” then
      set multNum to 6
    else if numStrWithMetric ends with “Z” then
      set multNum to 7
    else if numStrWithMetric ends with “Y” then
      set multNum to 8
      
    else
      return false
    end if
    
    
set aCMD to “echo \” scale=10; “ & aBaseStr & “^” & (multNum as string) & “*” & numPart & “\” | bc”
    
set aRes to do shell script aCMD
    
return aRes
    
  else
    return false
    
  end if
end procMetricPrefix

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/04/29 文字列で指定したラベルの値をレコードから取得する v2

レコード型データ(例:{myAge:25, myData:”ABCDEFG”})から属性ラベルを変数で指定して属性値を取得するAppleScriptです。

レコード型のデータから任意の属性値を取り出すことは可能ですが、属性ラベルをプログラム内に直接記述する必要があります。

  set aRec to {myAge:25, myData:”ABCDEFG”}
  set a to myAge of aRec
  –> 25

このように、もともとのAppleScriptの言語仕様では属性ラベルを間接的に指定する方法が用意されておらず、そのままでは使い勝手がいまひとつです。

しかし、たいていの言語処理系には、言語仕様を超える処理を行うための仕組みが用意されています(用意されていないケースもあります)。AppleScriptの場合だと、それは「run script」コマンドです。文字列で組み立てたAppleScriptのプログラムをそのまま実行して結果を返します。

そんなrun scriptコマンドを用いて、けっこー昔に少々トリッキーな手を使って、間接的に(変数で属性ラベルを)指定して属性値を取り出せるようにしてみました

最初に作ったときにはレコード内容をファイルに書き出すなど、かなり大掛かりな方法を使っていたのですが、その後いろいろ「手口」が洗練され、ファイルに書き出す必要がないことも分りました。海外のユーザーと情報交換を行って、どんどん洗練されていったわけです。

さらに、エラートラップを用いてレコードを文字列化する場合に、言語環境(日本語)に限定されない処理に書き換えたものが本バージョンです。

最初は、Mac OS X上のすべての言語環境に対応するため、(指定可能なすべての)言語ロケール情報を地道に調べて条件分けしていたのですが、

  if aLoc is in {”af”, “sq”, “am”, “ar”, “as”, “az”, “eu”, “be”, “bn”, “bs”, “br”, “bg”, “my”, “ca”, “chr”, “zh”, “hy”, “en”, “fr”, “de”, “it”} then
    –たいていの言語のエラーメッセージは英語なので、同様の対処でOK
    set b to trimStrFromTo(a, “{”, “}”)
    set b to “{” & b & “}”
  else if aLoc = “ja” then
    –Japanese(日本語の場合の対応)
    set b to repChar(a, “のタイプを string に変換できません。”, “”)
  end if

よくよく考えたら(日本語を含む)すべての言語環境で同じ処理でよいことが分り、このようなプログラムに落ち着きました。

sandbox化したAppleScriptObjCのプログラム中で、自由度が高すぎる「run script」文の使用が禁止されたりしたら……高度な処理が行えず、かなり困ることになりますが……Appleとしても様子を見ているところなんでしょう(あるいは、そこまで担当者が気付いていないかのどちらか)。

スクリプト名:文字列で指定したラベルの値をレコードから取得する v2
set aRec to {myAge:36, myHight:166, myWeight:70}
set aLabel to “myHight”

set a to getSpecifiedAttrOfRec(aRec, aLabel) of me
–> 166

–与えられたレコードから指定の属性値ラベルの値を取り出して返す
on getSpecifiedAttrOfRec(aRec, aLabel)
  
  
–パラメータのエラーチェック。エラー時にはmissing valueを返す
  
set aClass to class of aRec
  
if aClass is not record then return missing value
  
if aLabel = “” then return missing value
  
if class of aLabel is not string then return missing value
  
  
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
  
try
    set a to aRec as string
  on error aMes
    set a to aMes
  end try
  
  
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
  
set b to trimStrFromTo(a, “{”, “}”)
  
set b to “{” & b & “}”
  
  
–動的にAppleScriptを生成して、無理矢理レコードから目的の属性値を取り出す
  
set s to “return “ & aLabel & ” of “ & b
  
try
    set recData to run script s
  on error
    return missing value –指定の属性値が存在しなかった場合にはエラー
  end try
  
  
return recData
  
end getSpecifiedAttrOfRec

on trimStrFromTo(aStr, fromStr, toStr)
  –fromStrは前から探す
  
if fromStr is not equal to “” then
    set sPos to (offset of fromStr in aStr) + 1
  else
    set sPos to 1
  end if
  
  
–toStrは後ろから探す
  
if toStr is not equal to “” then
    set b to (reverse of characters of aStr) as string
    
set ePos to (offset of toStr in b)
    
set ePos to ((length of aStr) - ePos)
  else
    set ePos to length of aStr
  end if
  
set aRes to text sPos thru ePos of aStr
  
return aRes
end trimStrFromTo

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v5

ルールにのっとったコード全生成サブルーチン v4の改良版です。このv5でひとまずの完成を見ています。

本バージョンでは、コードルールから「初期値」を求める機能を追加し、これでルールのリストだけ与えれば、該当するすべてのパターンのコードを生成できるようになりました。

こうして、最初のv1から見直してみると……ずいぶんとコンパクトになりました。当初は持っていなかった汎用性を獲得し、だいたいこんな感じではないか、という自己満足に到達することはできました。

もっと難しいかと思っていたのですが、段階的に進化させていくことで「あっけなくできた」感じがします。最初から高機能なものを作ろうとせずに、動作が確認できる程度の簡単なものを作って、徐々に機能を向上させていくというやりかたは、実に強力です。

スクリプト名:指定のコード体系の全パターンのコードを生成 v5
–v5 外部からプロパティで与えられたルールから、初期値となる「最小値」を自前で計算するように変更
–v4 桁ごとにサブルーチンを設けるのではなく、再帰処理で1つのルーチンを多重呼び出しするように変更
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}} –各桁の{最小値, 最大値}ペアのリスト
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {} –initilaize

set initNum to getMinNum() of me –本ルール下における最小値

set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit(aNum, 1) of me
  
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–与えられたルール下における最小値をルールリストから求める
on getMinNum()
  –桁数が合っているだけのダミー数字を、適切な桁数作成する(例:11111)
  
set tmpNumStr to “”
  
repeat (aRuleLen of spd) times
    set tmpNumStr to tmpNumStr & “1″
  end repeat
  
  
set tmpNum to tmpNumStr as integer
  
  
–ルールから各桁の最小値を取り出して、各桁に設定する
  
repeat with i from 1 to (aRuleLen of spd)
    set aDigNum to item 1 of item i of (aRuleList of spd)
    
set tmpNum to setDigit(tmpNum, i, aDigNum) of me
  end repeat
  
  
return tmpNum
  
end getMinNum

–繰り上がり処理(再帰呼び出しで使用)
on incDigit(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    
    
if aDigit = (aRuleLen of spd) then
      –オーバーフロー(桁あふれ)エラーを返す
      
return false
    end if
    
    
set bNum to incDigit(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
    
  else
    
    
set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
    
  end if
  
  
return bNum
  
end incDigit

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v4

ルールにのっとったコード全生成サブルーチン v3の改良版です。このバージョンでは、これまで各桁ごとに専用のサブルーチンを設けて使っていたところを、全桁共通サブルーチンとして、コードの桁数を変更可能にしました。

いちおう、目指していた機能はすべて実現できた「完成版」といえます。

ただ……実際に作ってみないと気付かない点はあるもので、このプログラム……ルールで与えたコード体系の「最小値」を初期値として与えてあげないとダメなのですが、これを人間がパラメータとして書いてあげる必要があります。これはいただけません。

この初期値をルールから自動で生成するようにして、はじめてルールとロジックの分離が完了するといえるでしょう。

スクリプト名:指定のコード体系の全パターンのコードを生成 v4
–v4 桁ごとにサブルーチンを設けるのではなく、再帰処理で1つのルーチンを多重呼び出しするように変更
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}} –各桁の{最小値, 最大値}ペアのリスト
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011 –本ルール下における最小値。この値も本来は計算から求めるべき
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit(aNum, 1) of me
  
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–繰り上がり処理(再帰呼び出しで使用)
on incDigit(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    
    
if aDigit = (aRuleLen of spd) then
      –オーバーフロー(桁あふれ)エラーを返す
      
return false
    end if
    
    
set bNum to incDigit(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
    
  else
    
    
set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
    
  end if
  
  
return bNum
  
end incDigit

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v3

ルールにのっとったコード全生成サブルーチン v2の改良版です。このバージョンでは、処理ロジックとデータの分離が完了しています。

プロパティに {最小値, 最大値} のペアを桁数分だけ書いておくと、そのルールにもとづいて数値コードを生成します。この最小値/最大値には1桁の数値を指定することを想定しています。

このあたり……前提条件を無視して2桁以上の数値を指定したりすると、正しく動作しないと思います。また、10進数専用で考えています。このあたりの前提条件はこのコード生成シリーズで共通の仕様です。

スクリプト名:指定のコード体系の全パターンのコードを生成 v3
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}}
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum, 1) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit2(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit3(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit4(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit5(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v2

ルールにのっとったコード全生成サブルーチン v1の改良版です。まずは、処理ロジックとルールの分離をテストする意味で、ルールの書き方をテストし、各サブルーチンから参照できているかどうか、テストを行いました。

ここまで書いてみると、各桁のインクリメントを受け持つサブルーチンを共通化できそうな感じがしてきました。最初から、その方向に進化させるつもりで書き出したものですが、これならいけそうだという感触を得るには実際に書いてみないと。

スクリプト名:指定のコード体系の全パターンのコードを生成 v2
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}}
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum)
  
  
set {thisMin, thisMax} to item (aRuleLen of spd) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 1) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit2(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 1, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 1, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 2) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit3(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 2, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 2, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 2) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 3) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit4(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 3, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 3, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 3) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 4) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit5(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 4, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 4, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 4) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 5) of me
  
  
if aTarget = thisMax then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 5, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v1

製品コードやテストパターンを反映させたファイル名を作成するような場合に、ルールに基づいてコードチェックをするようなAppleScriptのサブルーチンは作っていました。

→ コードのチェック
→ 簡易マクロ展開つきのコードチェック v1

とりあえず、何も考えずに当該桁数の数値を(数十万個とか)すべて作成しておいて、ルールに合致するものだけをフィルタリングして残す……みたいな、あまり考えずにマシンパワーに依存して「ルールに基づいたコードの全生成」をやっていたのですが、いつも恥ずかしく思っていました。

そこで、ルールに基づいたコード(だけ)を全パターン生成するサブルーチンを作ることを決意。

最初に、各桁のコード生成ルールを各桁ごとの専用のサブルーチンで扱うようにして、繰り上がりが発生したら上位桁のインクリメント(+1)ルーチンを呼ぶようにしてみました。

きちんと、目的を達してくれますし……後に登場する高機能ルーチンよりも高速です(とはいえ、みんな実行に1秒もかかっていないのですが)。想定しているパターンのコード番号をすべて生成してくれます。

生成例:
–> {11011, 11012, 11013, 11014, 11015, 11016, 11017, 11018, 11021, 11022, 11023, 11024, 11025, 11026, 11027, 11028, 11031, 11032, 11033, 11034, 11035, 11036, 11037, 11038, 11041, 11042, 11043, 11044, 11045, 11046, 11047, 11048, 11111, 11112, 11113, 11114, 11115, 11116, 11117, 11118, 11121, 11122, 11123, 11124, 11125, 11126, 11127, 11128, 11131, 11132, 11133, 11134, 11135, 11136, 11137, 11138, 11141, 11142, 11143, 11144, 11145, 11146, 11147, 11148, 12011, 12012, 12013, 12014, 12015, 12016, 12017, 12018, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12031, 12032, 12033, 12034, 12035, 12036, 12037, 12038, 12041, 12042, 12043, 12044, 12045, 12046, 12047, 12048, 12111, 12112, 12113, 12114, 12115, 12116, 12117, 12118, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12131, 12132, 12133, 12134, 12135, 12136, 12137, 12138, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 13011, 13012, 13013, 13014, 13015, 13016, 13017, 13018, 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13038, 13041, 13042, 13043, 13044, 13045, 13046, 13047, 13048, 13111, 13112, 13113, 13114, 13115, 13116, 13117, 13118, 13121, 13122, 13123, 13124, 13125, 13126, 13127, 13128, 13131, 13132, 13133, 13134, 13135, 13136, 13137, 13138, 13141, 13142, 13143, 13144, 13145, 13146, 13147, 13148, 21011, 21012, 21013, 21014, 21015, 21016, 21017, 21018, 21021, 21022, 21023, 21024, 21025, 21026, 21027, 21028, 21031, 21032, 21033, 21034, 21035, 21036, 21037, 21038, 21041, 21042, 21043, 21044, 21045, 21046, 21047, 21048, 21111, 21112, 21113, 21114, 21115, 21116, 21117, 21118, 21121, 21122, 21123, 21124, 21125, 21126, 21127, 21128, 21131, 21132, 21133, 21134, 21135, 21136, 21137, 21138, 21141, 21142, 21143, 21144, 21145, 21146, 21147, 21148, 22011, 22012, 22013, 22014, 22015, 22016, 22017, 22018, 22021, 22022, 22023, 22024, 22025, 22026, 22027, 22028, 22031, 22032, 22033, 22034, 22035, 22036, 22037, 22038, 22041, 22042, 22043, 22044, 22045, 22046, 22047, 22048, 22111, 22112, 22113, 22114, 22115, 22116, 22117, 22118, 22121, 22122, 22123, 22124, 22125, 22126, 22127, 22128, 22131, 22132, 22133, 22134, 22135, 22136, 22137, 22138, 22141, 22142, 22143, 22144, 22145, 22146, 22147, 22148, 23011, 23012, 23013, 23014, 23015, 23016, 23017, 23018, 23021, 23022, 23023, 23024, 23025, 23026, 23027, 23028, 23031, 23032, 23033, 23034, 23035, 23036, 23037, 23038, 23041, 23042, 23043, 23044, 23045, 23046, 23047, 23048, 23111, 23112, 23113, 23114, 23115, 23116, 23117, 23118, 23121, 23122, 23123, 23124, 23125, 23126, 23127, 23128, 23131, 23132, 23133, 23134, 23135, 23136, 23137, 23138, 23141, 23142, 23143, 23144, 23145, 23146, 23147, 23148}

ただ、このままだとぜんぜん汎用性がないので……このレベルに安住していてはいけません。

スクリプト名:指定のコード体系の全パターンのコードを生成 v1
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum)
  
  
set aTarget to getDigit(aNum, 1) of me
  
  
if aTarget = 8 then
    set bNum to incDigit2(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 1, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 1, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum)
  
  
set aTarget to getDigit(aNum, 2) of me
  
  
if aTarget = 4 then
    set bNum to incDigit3(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 2, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 2, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum)
  
  
set aTarget to getDigit(aNum, 3) of me
  
  
if aTarget = 1 then
    set bNum to incDigit4(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 3, 0) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 3, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum)
  
  
set aTarget to getDigit(aNum, 4) of me
  
  
if aTarget = 3 then
    set bNum to incDigit5(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 4, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 4, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum)
  
  
set aTarget to getDigit(aNum, 5) of me
  
  
if aTarget = 2 then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 5, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/01/19 与えられたICC Profileの名称リストからもっともバージョンの新しい(大きい)数字を持つものを返す

同一の名称でバージョン番号のみ異なるICC Profile名称リストから、もっともバージョンの新しい(バージョン番号の数字が大きい)ものを抽出して返すAppleScriptです。

なお、バージョン番号数字が登場する箇所は1ブロックのみと仮定しており、複数ブロックに数字が出現するようなパターンは想定していません。

想定している : XXXXXX1.0.3xxxx.icc
想定していない: X3X4XX1.0.3xxxx.icc

ただ、このようにバージョン番号以外の場所に数字の文字があったとしても、実用上は問題ないものと判断しています。

X3X4XX1.0.3xxxx.icc
X3X4XX10.0.2xxxx.icc
X3X4XX5.0.1xxxx.icc

スクリプト名:与えられたICC Profileの名称リストからもっともバージョンの新しい(大きい)数字を持つものを返す
set a to {“Piyomaru Piyopiyo V4.0.icc”, “Piyomaru Piyopiyo V10.0.2.icc”, “Piyomaru Piyopiyo V10.0.1.icc”, “Piyomaru Piyopiyo V5.0.icc”}
set b to retLatestVersionICCprofileNameFromList(a, “.icc”)

–> “Piyomaru Piyopiyo V10.0.2.icc”

–与えられたICC Profileの名称リストからもっともバージョンの新しい(大きい)数字を持つものを返す
on retLatestVersionICCprofileNameFromList(a, aExt)
  
  
set allList to {}
  
  
–与えられたリストの各要素に対して、所定の拡張子を外したのちに数字部分だけを抽出
  
set allCount to 1
  
repeat with ii in a
    
    
set jj to contents of ii
    
set b to repChar(jj, aExt, “”)
    
    
set bList to characters of b
    
set nList to {}
    
    
repeat with i in bList
      set j to contents of i
      
if j is in {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”} then
        set the end of nList to j
      end if
    end repeat
    
    
–小数点が複数個登場する(かもしれない)文字列を評価して、普通の数値に変換する
    
set nStr to nList as string
    
set nStrNum to interpretNumStrAsNum(nStr)
    
    
    
–ソート用リストに、抽出した数値とアイテム番号を追加する
    
set the end of allList to {nStrNum, allCount}
    
    
set allCount to allCount + 1
  end repeat
  
  
  
–取り出した数値部分だけをキーにして降順ソート(大きな数→小さな数)
  
set resList to shellSortListDecending(allList, 1)
  
set {fData, fOrder} to first item of resList
  
  
set newestData to contents of item fOrder of a
  
  
return newestData
  
end retLatestVersionICCprofileNameFromList

–「10.7.3」などの複数のピリオドが入る数字の文字列を数値として解釈して返す
on interpretNumStrAsNum(a)
  
  
set {strCount, posList} to countAcharInStrAndDetectPos(a, “.”)
  
  
–ターゲット文字が複数回出現した場合
  
if strCount > 1 then
    set firstPosNum to first item of posList
    
    
if firstPosNum > 1 then
      –通常パターン
      
set aStr to text 1 thru firstPosNum of a
      
set bStr to text (firstPosNum + 1) thru -1 of a
      
set b2Str to repChar(bStr, “.”, “”)
      
      
set c to aStr & b2Str
    else
      –先頭に小数点が入っている場合
      
set aStr to text 2 thru -1 of a
      
set b2Str to repChar(aStr, “.”, “”)
      
      
set c to “0.” & b2Str –小数点が冒頭にあったので先頭に「0」を足した
    end if
    
  else
    –ターゲット文字(小数点)が1回のみ出現した場合
    
set c to a
  end if
  
  
set cNum to c as number
  
  
return cNum
  
end interpretNumStrAsNum

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

–文字列中に指定文字が何個入っているかカウントし、登場位置をリストで返す
on countAcharInStrAndDetectPos(aStr, aTargChar)
  set aList to {}
  
set posC to 1
  
  
considering case
    set aHit to offset of aTargChar in aStr
    
    
if aHit is not equal to 0 then
      set aaList to characters of aStr
      
set aCount to 0
      
      
repeat with i in aaList
        
        
set j to contents of i
        
        
if j = aTargChar then
          set aCount to aCount + 1
          
set the end of aList to posC
        end if
        
        
set posC to posC + 1
        
      end repeat
      
      
return {aCount, aList}
    else
      return {0, {}}
    end if
  end considering
end countAcharInStrAndDetectPos

–シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) > (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListAscending

–シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) < (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListDecending

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/01/19 複数のピリオドが入る数字の文字列を数値として解釈して返す

“10.8.3″などのピリオドが複数入った数字の文字列を数値(10.83)として評価して返すAppleScriptです。

システムにインストールされた特定のモジュールの、各名称につけられたバージョン番号を考慮し、同一名称でバージョン番号が大きい(=新しい)ものをピックアップするときに作成しました。

元の文字列をそのままソートすると、10.8よりも5.1のほうが「大きい」ものとして評価されてしまい、都合がよろしくありません。

なにげなく「こういうケースが発生したらまずい」と気付いて作り出したら……予想外に巨大なプログラムになってしまいました。もっと簡単な方法がありそうではありますが、とりあえず期待どおりの動作を行ってくれています。

スクリプト名:複数のピリオドが入る数字の文字列を数値として解釈して返す
set a to ".2.1.3"
set b to interpretNumStrAsNum(a)
–> 0.213

set a to "23"
set b to interpretNumStrAsNum(a)
–> 23

set a to "10.0.1"
set b to interpretNumStrAsNum(a)
–> 10.01

set a to "10.0.1.2.3.4"
set b to interpretNumStrAsNum(a)
–> 10.01234

–「10.7.3」などの複数のピリオドが入る数字の文字列を数値として解釈して返す
on interpretNumStrAsNum(a)
  
  
set {strCount, posList} to countAcharInStrAndDetectPos(a, ".")
  
  
–ターゲット文字が複数回出現した場合
  
if strCount > 1 then
    set firstPosNum to first item of posList
    
    
if firstPosNum > 1 then
      –通常パターン
      
set aStr to text 1 thru firstPosNum of a
      
set bStr to text (firstPosNum + 1) thru -1 of a
      
set b2Str to repChar(bStr, ".", "")
      
      
set c to aStr & b2Str
    else
      –先頭に小数点が入っている場合
      
set aStr to text 2 thru -1 of a
      
set b2Str to repChar(aStr, ".", "")
      
      
set c to "0." & b2Str –小数点が冒頭にあったので先頭に「0」を足した
    end if
    
  else
    –ターゲット文字(小数点)が1回のみ出現した場合
    
set c to a
  end if
  
  
set cNum to c as number
  
  
return cNum
  
end interpretNumStrAsNum

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

–文字列中に指定文字が何個入っているかカウントし、登場位置をリストで返す
on countAcharInStrAndDetectPos(aStr, aTargChar)
  set aList to {}
  
set posC to 1
  
  
considering case
    set aHit to offset of aTargChar in aStr
    
    
if aHit is not equal to 0 then
      set aaList to characters of aStr
      
set aCount to 0
      
      
repeat with i in aaList
        
        
set j to contents of i
        
        
if j = aTargChar then
          set aCount to aCount + 1
          
set the end of aList to posC
        end if
        
        
set posC to posC + 1
        
      end repeat
      
      
return {aCount, aList}
    else
      return {0, {}}
    end if
  end considering
end countAcharInStrAndDetectPos

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/06/30 8ビットの2進数文字列を10進数に戻す

“1″と”0″で構成された8ビットの2進数文字列を評価して10進数に変換するAppleScriptです。

「エンコーダーを作ったらデコーダーも作れ」(逆もしかり)というのは、もはや常識を通り越して当たり前な話なわけですが、「ちょっとした気の迷い」で作った2進数エンコーダーのおまけにデコーダーを作るのは、さほど行数は長くならないことが分かっていたとしても、けっこう気が滅入ります。

おもえば……作る前に「こんなの誰かが作って公開しているだろう」と考えて、探さなかったところに敗因が……

bin2.png

スクリプト名:8ビットの2進数文字列を10進数に戻す
set aStr to “11110100″
set aNum to binaryDecode(aStr) of me
–> 244

–8ビットの2進数文字列を10進数に戻す
on binaryDecode(aStr)
  –エラーチェック
  
set aLen to length of aStr
  
if aLen is not equal to 8 then return false
  
  
set aNum to 0
  
repeat with i from 7 to 0 by -1
    set aCon to contents of character (8 - i) of aStr
    
    
if aCon = “1″ then
      set aNum to aNum + (2 ^ i)
    end if
    
  end repeat
  
  
return aNum as integer
  
end binaryDecode

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/06/30 0〜255の範囲の10進数を2進数の文字列に変換して返す

10進数の数値を8ビットの2進数文字列に変換して返すAppleScriptです。

ビット演算を行うさいに、別に2進数文字列を経由しないで計算することはできるわけですが、デバッグの都合上どうしても2進数の文字列で見えたほうがよいとの理由で作ってみました。

そもそも最初は、IEEE754の浮動小数点形式の4バイト(32ビット)のデータを作ろうと思いたち、そのためにこのバイナリ文字列エンコーダーとかバイナリ文字列デコーダーとかを作り出して、ついでもあるのでビットシフト演算やローテート演算など……(人間の言葉に近いという意味の)超高級言語のAppleScriptで、CPUのアセンブリコード並みの超低級言語に出てくる演算を実装しているのがシュールです。

bin1.png

スクリプト名:0〜255の範囲の10進数を2進数の文字列に変換して返す
set aNum to 244
set aStr to binaryEncode(aNum) of me
–> "11110100"

–0〜255の範囲の10進数を2進数の文字列に変換して返す
on binaryEncode(aNum)
  –エラーチェック
  
if aNum < 0 or 255 < aNum then return false
  
  
set bitStr to ""
  
  
repeat with i from 7 to 0 by -1
    try
      set aRes to aNum div (2 ^ i)
      
set aNum to aNum mod (aRes * (2 ^ i))
    on error
      set aRes to 0
    end try
    
    
set aRes to aRes as integer
    
set bitStr to bitStr & (aRes as string)
  end repeat
  
  
return bitStr
  
end binaryEncode

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/06/06 日本語数値表現エンコードされた数値のparseテスト v2

日本語的数値表現された数値文字列テキスト(「3無量大数」とか「5恒河沙」とか)を数値部分と桁インジケータ日本語文字列に分ける(parseする)AppleScriptです。

以前に作ったものが気に入らなかったので、作り直しました。

ちなみに、最近(Mac OS X 10.6以降)もっぱら日本語のparseが賢くなったという評判の、「words of」でparseすると…………残念な結果に。

# 本ルーチンにはバグが見つかったため、新しいバージョンをご参照ください

スクリプト名:日本語数値表現エンコードされた数値のparseテスト v2
property scaleList : {“万”, “億”, “兆”, “京”, “垓”, “丈”, “壌”, “溝”, “砂”, “正”, “載”, “極”, “恒河沙”, “阿僧梢”, “那由他”, “不可思議”, “無量大数”}

set a to “10無量大数9997那由他9297載6866正6832砂1967溝1163壌4317丈7692垓2493京8466兆7286億6441万8111″
set b to parseJapaneseEncodedNumericText(a, scaleList) of me
–> {”1″, “0″, “無量大数”, “9″, “9″, “7″, “那由他”, “2″, “9″, “7″, “載”, “8″, “6″, “6″, “正”, “8″, “3″, “2″, “砂”, “9″, “6″, “7″, “溝”, “1″, “6″, “3″, “壌”, “3″, “1″, “7″, “丈”, “6″, “9″, “2″, “垓”, “4″, “9″, “3″, “京”, “4″, “6″, “6″, “兆”, “2″, “8″, “6″, “億”, “4″, “4″, “1″, “万”, “1″, “1″, “1″}

set a to “10無量大数”
set b to parseJapaneseEncodedNumericText(a, scaleList) of me
–> {”1″, “0″, “無量大数”}

–日本語エンコーディングされた数値テキストをparseする
–拾壱などの昔の漢字ベースの数字については、別途、「日本語数値表現文字列プリプロセッサ」にて置換処理すること
–十百千万の各文字がscaleListに入っていないことが動作条件(大丈夫)
on parseJapaneseEncodedNumericText(a, scaleList1)
  –桁識別子のリスト自体をバラバラにする
  
set scaleList2 to {}
  
repeat with i in scaleList1
    set j to contents of i
    
set tmpList to characters of j
    
set scaleList2 to scaleList2 & tmpList
  end repeat
  
  
–パラメータを文字単位で分解して、「桁識別子に入っている文字のリスト」(scaleList2)を照合しつつparseする
  
set aList to characters of a
  
  
set newList to {}
  
  
set hitF to false
  
set tmpBuff to “”
  
  
repeat with i in aList
    
    
set j to contents of i
    
    
–対象文字が日本語数値表現エンコーディングに使われている文字のリスト に入っている場合
    
if j is in scaleList2 then
      
      
if hitF = false then
        –立ち上がり
        
set tmpBuff to j
        
set hitF to true
        
      else if hitF = true then
        –継続状態
        
set tmpBuff to tmpBuff & j
      end if
      
    else
      –対象文字が日本語数値表現エンコーディングに使われている文字のリストに 入っていない場合
      
if hitF = true then
        –日本語数値表現エンコーディングに使われている文字列の末尾を検知した
        
set the end of newList to tmpBuff
        
set hitF to false
        
set tmpBuff to “”
        
      else
        –通常の数字などはここで処理
        
set the end of newList to j
        
      end if
      
    end if
  end repeat
  
  
–末尾に日本語数値表現エンコーディング桁文字列が入っていた場合への対処(バッファ出力)
  
if tmpBuff is not equal to “” then
    set the end of newList to tmpBuff
  end if
  
  
return newList
  
end parseJapaneseEncodedNumericText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/02/03 近似式によるRGB→CMYK/CMYK→RGB変換

AppleScriptでRGBの色データをCMYKの色データに変換する手段といえば、Color Sync Scirpingを用いるのが常套手段だったのですが、これがMac OS X 10.6で廃止になりました(残念!)。

・OS X 10.7, LionのRelease Noteに書かれていない変更点
http://piyocast.com/as/archives/1751

ほかに、色データの変換を行う手段といえば、安直にPhotoshopに計算してもらうというものもあります。こちらは、現在でも(Photoshopが入っている環境であれば)利用できます。

・与えられたテキストをPhotoshopでRGBデータと評価してCMYK値を返す
http://piyocast.com/as/archives/1898

ほかには、AppleScriptObjCが使えれば、NSColorのgenericCMYKcolorSpaceを用いて変換することも可能です。genericなCMYKcolorSpaceだけでなく、出力デバイス名を指定して出力特性を反映させて変換を行うことも可能です(genericしか試してないけど)。

……で、これらの手段が使えない場合にどうするかといえば、RGB→CMYK/CMYK→RGBの変換を行う「近似式」があるため、それを使うのが一般的です。

・ISP imaging-developers-色変換式集 - CMYK
http://image-d.isp.jp/commentary/color_cformula/CMYK.html

この近似式を用いた(Objective-Cで書かれた)プログラムの処理結果が思わしくないということだったので、AppleScriptで近似式を用いて相互変換の処理を書いてみました。

RGB→CMYK変換では、黒に近い色(というか黒)を与えると0による除算が発生したり、マイナスの値になったりするケースが見られたため、try〜end tryでエラーをキャッチしたりするなど、地道な補正を加えています。

本Scriptでは、choose colorコマンドで指定した色(RGB)を一度CMYKに変換し、変換したCMYK値を再度RGB値に変換してchoose colorコマンドで色プレビューを行っています。

RGB→CMYKの変換時に発生する一種の「くすみ」がなく、見たまんまそのまま変換されてしまうので、分る人が見るとウソだと分るのですが、単に変換したいだけという場合には割と使えるという感触です。

スクリプト名:指定色をRGB→CMYK→RGB変換プレビュー
–色選択
set aCol to choose color

set {rNum, gNum, bNum} to aCol

set rNum to rNum div 255
set gNum to gNum div 255
set bNum to bNum div 255

–RGB→CMYK変換
set {cNum, mNum, yNum, kNum} to approximateRGBtoCMYKconvert(rNum, gNum, bNum) of me

–CMYK→RGB変換
set {rNum2, gNum2, bNum2} to approximateCMYKtoRGBconvert(cNum, mNum, yNum, kNum) of me

set rNum2 to 65535 * rNum2
set gNum2 to 65535 * gNum2
set bNum2 to 65535 * bNum2

–色プレビュー
choose color default color {rNum2, gNum2, bNum2}

–近似式ベースのRGB→CMYK変換
–参照資料:
–http://image-d.isp.jp/commentary/color_cformula/CMYK.html
on approximateRGBtoCMYKconvert(r, g, b)
  
  
set rNum to r / 255
  
set gNum to g / 255
  
set bNum to b / 255
  
  
set nList to {1 - rNum, 1 - gNum, 1 - bNum}
  
  
set kNum to minimumFromList(nList) of me
  
  
–kNum(Black)がマイナスになるケースがあるため、値を補正
  
if kNum < 0 then set kNum to 0
  
  
  
–0による除算が発生した場合の算術エラーに対処
  
try
    set cNum to (1 - rNum - kNum) / (1 - kNum)
  on error
    set cNum to 0
  end try
  
  
–0による除算が発生した場合の算術エラーに対処  
  
try
    set mNum to (1 - gNum - kNum) / (1 - kNum)
  on error
    set mNum to 0
  end try
  
  
–0による除算が発生した場合の算術エラーに対処  
  
try
    set yNum to (1 - bNum - kNum) / (1 - kNum)
  on error
    set yNum to 0
  end try
  
  
  
–C/M/Yがマイナスになるケースがあるため、値を補正
  
if cNum < 0 then set cNum to 0
  
if mNum < 0 then set mNum to 0
  
if yNum < 0 then set yNum to 0
  
  
  
return {cNum, mNum, yNum, kNum}
  
end approximateRGBtoCMYKconvert

–近似式ベースのCMYK→RGB変換
–参照資料:
–http://image-d.isp.jp/commentary/color_cformula/CMYK.html
on approximateCMYKtoRGBconvert(c, m, y, k)
  
  
set rNum to 1 - (minimumFromList({1, c * (1 - k) + k}))
  
set gNum to 1 - (minimumFromList({1, m * (1 - k) + k}))
  
set bNum to 1 - (minimumFromList({1, y * (1 - k) + k}))
  
  
return {rNum, gNum, bNum}
  
end approximateCMYKtoRGBconvert

–最小値を取得する
on minimumFromList(nList)
  script o
    property nl : nList
  end script
  
  
set min to item 1 of o’s nl
  
repeat with i from 2 to (count nList)
    set n to item i of o’s nl
    
if n < min then set min to n
  end repeat
  
return min
  
end minimumFromList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/09/04 簡単な素因数分解v2

簡単な素因数分解を行うAppleScriptのバージョン2です。

バージョン1では素因数分解を行うだけでしたが、バージョン2では約数を同時に返すようにしました。

素因数分解を行っただけでは、構成要素となる素数がバラバラに取得できるだけで、約数については素因数分解を行った要素から総当たりで作る必要があり、そのあたりがちょっとお手軽に結果が得られない雰囲気。

そこで、素因数分解を行う最中に出てきた数値を別途記録しておくことで、それっぽい約数が得られて一石二鳥。

ただし、だんだん素因数分解を行うことが目的化してきたことに気付いて、あわてて本来の問題解決のためのプログラムを別途作ることに…………。

スクリプト名:簡単な素因数分解v2
set a to 64
set {b1List, b2List} to returnDivisor(a) of divisorKit
–> {{2, 2, 2, 2, 2, 2}, {32, 16, 8, 4, 2}}

–簡単な素因数分解
script divisorKit
  on returnDivisor(a)
    –1000以下の素数のリスト (prime number list under 1000)
    
set primeNum1000 to {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997}
    
    
if a > 1000 then return false –1000より大きかったらfalseをリターン(計算範囲外エラー)
    
    
if a is in primeNum1000 then
      return true –1000までの数字で、素数だった場合
    end if
    
    
–ここからメイン処理
    
set divisorList to {} –約数のリスト
    
set ansList to {} –元の数を約数で割ったときの商のリスト
    
    
repeat while a > 0
      set {r1, r2} to returnDivisorSub(a, primeNum1000) of me
      
if r1 = false then exit repeat
      
      
set the end of divisorList to r1
      
      
–計算結果リストに1が入ることを防ぐ
      
if r2 is not equal to 1 then
        set the end of ansList to r2
      end if
      
      
set a to r2
    end repeat
    
    
return {divisorList, ansList}
    
  end returnDivisor
  
  
  
on returnDivisorSub(a, primeNumList)
    repeat with i in primeNumList
      set a1 to a div i
      
set a2 to a / i
      
if a1 = a2 then
        return {contents of i, a1}
      end if
    end repeat
    
return {false, false}
  end returnDivisorSub
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/09/02 簡単な素因数分解

簡単な素因数分解を行うAppleScriptです。

簡単な……というのは、1000までの数に処理対象を限定しているのと、あんまりしっかり検証していないので「あ、動くからいいや」ぐらいの完成度のためです。実務で長年ビシバシにいじめまくって、これなら大丈夫……というほど裏がとれているわけでもない、というレベルです。

そもそも、なんでまた素因数分解などを作ろうと考えたかといえば、InDesign上のオブジェクトにスクリプトラベルをつける作業をしていたときに、最近こういう作業はぜんぶAppleScriptから自動で採番して実行するのですが、ラベルを付ける対象が数百個にも達し、しかもそれらが整然と並んでいるため、

 「縦に何個並んでいるか、全体の個数から勝手に判断してくれたらいいのに〜!」

などと、ふと思ってしまったからで、「じゃあ、要素数を素因数分解して、適当な候補数をchoose from listで表示してくれたらいいな〜」などと、あまり考えずに勢いだけで作りはじめたのがきっかけです(長いな)。

素因数分解などとおおげさなことを言っても、しょせんは素数で割ったリストにすぎないので、1から1000までの素数のリストを取り寄せて、割り算しながらループを回すというお気楽仕様に。思い立ってから出来上がるまで、10分ぐらい。

これで結局役に立たなくて、version 2を作る羽目になるのですが……。

スクリプト名:簡単な素因数分解
set a to 312
set b to returnDivisor(a) of divisorKit
–> {2, 2, 2, 3, 13}

–簡単な素因数分解
script divisorKit
  on returnDivisor(a)
    –1000以下の素数のリスト (prime number list under 1000)
    
set primeNum1000 to {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997}
    
    
if a > 1000 then return false –1000より大きかったらfalseをリターン(計算範囲外エラー)
    
    
if a is in primeNum1000 then
      return true –1000までの数字で、素数だった場合
    end if
    
    
–ここからメイン処理
    
set divisorList to {}
    
    
repeat while a > 0
      set {r1, r2} to returnDivisorSub(a, primeNum1000) of me
      
if r1 = false then exit repeat
      
      
set the end of divisorList to r1
      
      
set a to r2
    end repeat
    
    
return divisorList
  end returnDivisor
  
  
  
on returnDivisorSub(a, primeNumList)
    repeat with i in primeNumList
      set a1 to a div i
      
set a2 to a / i
      
if a1 = a2 then
        return {contents of i, a1}
      end if
    end repeat
    
return {false, false}
  end returnDivisorSub
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/13 数値の序数の文字列を返す

数値を渡すと、英語の序数(1st, 2ndなど)の文字列を返すAppleScriptです。

あまり面白味も何もないのですが、必要に迫られて作成したものです。1->1st、11->11th、21->21st……と、11,12,13の時だけ例外処理を行っています。

AppleScriptのsayコマンドに「11st」などと間違った序数を渡しても、「11th」と言い換えたりしているので、OS内部には序数の処理機能が入っているはずですが、ASからは利用できません。

単なるif文の塊になっていますが、まあこんな感じではないでしょうか。

スクリプト名:数値の序数の文字列を返す
repeat with i from 1 to 100
  set a to retOrdinalNumStr(i) of me
  
log a
end repeat

–数値を与えると序数の文字列を返す
on retOrdinalNumStr(aNum)
  set aStr to aNum as string
  
  
–下1桁の数字を取得
  
set last1Str to last character of aStr
  
  
–下2桁目の数字を取得
  
if length of aStr > 1 then
    set last2Str to character -2 of aStr
  else
    set last2Str to “”
  end if
  
  
–場合分け
  
set retStr to “”
  
if last1Str = “1″ then
    if last2Str = “1″ then
      set retStr to “th” –11
    else
      set retStr to “st”
    end if
    
  else if last1Str = “2″ then
    if last2Str = “1″ then
      set retStr to “th” –12
    else
      set retStr to “nd”
    end if
    
  else if last1Str = “3″ then
    if last2Str = “1″ then
      set retStr to “th” –13
    else
      set retStr to “rd”
    end if
    
  else
    set retStr to “th”
    
  end if
  
  
return aStr & retStr
  
end retOrdinalNumStr

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/11/28 変数値のスワップ

複数の変数の内容を入れ替えるAppleScriptサンプルです。

一度、他の変数に値を退避させて順次代入……などと回りくどいことをしなくても、一度に指定すればシンプルに記述できます。

InDesignドキュメントを2枚オープンして、ウィンドウの座標値からどちらが画面上の左に位置していて、どちらが右に位置しているかを検出。左側ドキュメントから右側ドキュメントにScript Labelを手がかりにデータを転送するAppleScriptを書いていたときに、これらの左右を入れ替える機能を実装する羽目になって、そういえば変数値のスワップって面倒かもしれない……などと思いながら、1行で書いてみたらたいへんにシンプルな記述で済んだ……ということがありました。

その時には変数にはInDesignのLayout Windowオブジェクトへの参照が入っていたわけですが、このような一番かんたんなレベルに立ち返ってその場で試してみて、挙動を確認しつつ実際のプログラムに反映させました。記述サンプルとしては、難しくて複雑なプログラムよりも、簡単で分りやすくて短いものの方が役立つことが多いように感じています。

スクリプト名:変数値のスワップ
set a to 1
set b to 2

set {a, b} to {b, a}
–> {2, 1}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

ちなみに……2つ以上の変数の場合でも、とくに問題はありません。

スクリプト名:変数値のスワップ2
set a to 1
set b to 2
set c to 3

set {a, b, c} to {c, b, a}
–> {3, 2, 1}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/11/25 擬似的にPropertyファイルを使ってカウントアップ

保存ファイルを~/Library/Preferencesに作成し、カウントアップを行います。

カウンター値を保持する場合には、propertyでScript中に保持しておくのが一番簡単ですが、AppleScriptのプログラムを書き換えてしまうと初期値に戻ってしまいます。そこで、初期設定ファイル(もどき)を作成して、リストの値をそのまま保存。こうしておけば、プログラムを書き換えて実行しても、カウント内容が維持されます。

本物のplistファイルで値を保持してもいいのですが、より簡単かつ安直にファイルに書き込んで使ってもよいだろう、というアプローチです。

スクリプト名:Propertyファイルを使ってカウントアップ
set aRes to countUp(“jp.piyomarusoft.counter.pref”) of countUpKit

script countUpKit
  –カウントアップ
  
on countUp(anIDentifier)
    set apDir to (path to preferences folder from user domain) as string
    
set a to apDir & anIDentifier
    
tell application “Finder”
      set fRes to exists of file a
      
if fRes = false then
        –初期設定ファイルがなければ初期化(1からカウントアップし直し)
        
write_to_file_AsList({1}, a) of me
        
return 1
      else
        set aCount to read file a as list
        
set aaCount to (item 1 of aCount as number) + 1
        
write_to_file_AsList(aaCount, a) of me
        
return aaCount
      end if
    end tell
  end countUp
  
  
–ファイルの追記ルーチン「write_to_file_AsList」  (リストとして書き込み)
  
–データ、対象ファイル
  
on write_to_file_AsList(this_data, target_file)
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
set eof of the open_target_file to 0
      
write this_data to the open_target_file starting at eof as list
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end write_to_file_AsList
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/09/19 Sin Cos演算ルーチン

三角関数のサイン、コサインを演算するサブルーチンです。海外でひろってきました。

先日、知人から「AppleScriptで三角関数を求めるための命令はないのか?」と聞かれたのですが、標準ではAppleScriptの処理系に三角関数を求める命令は入っていません。

サードパーティのOSAX(Scripting Additionとも呼ばれる)を見つけてきて、プログラミングを行うMacの環境および実行するMacの環境に同じOSAXをインストールしておく必要があります(バンドル形式のアプリケーションにして、バンドル内にOSAXを入れておくという手もあります)。

実際、仏Satimage Softwareが配布している「Satimage」OSAXにはSin/Cosをはじめとする数値関数の命令が入っています。たいていの場合にはこれを利用するのがよいでしょう。

ただし、どうしても実行環境にOSAXをインストールしたくないとか、どこで実行しても大丈夫なようにしておきたいという場合には、このような三角関数演算ルーチンを作ったり拾ってきたりすることになることでしょう。

または、たいてい近似値で済む場合が多いですし、パラメータに整数しか渡さないといった条件が整っている場合には、360度分のSinテーブル、Cosテーブルを作成しておいて、そこから求めるという手もあります。

以前に、Aboutメニューでいろんな文字が画面上を楕円運動するようなAppleScript Studioのアプリケーションを作ってみましたが、その時にはこのSin/Cosテーブルを用意して実装した次第です。

スクリプト名:Sin Cos演算ルーチン
set a to sine_of(47) of me
–> 0.731353701619

set b to cosine_of(71) of me
–> 0.325568154457

on sine_of(x)
  repeat until x 0 and x < 360
    if x 360 then
      set x to x - 360
    end if
    
if x < 0 then
      set x to x + 360
    end if
  end repeat
  
  
set x to x * (2 * pi) / 360 –convert from degrees to radians
  
  
set answer to 0
  
set numerator to x
  
set denominator to 1
  
set factor to -(x ^ 2)
  
  
repeat with i from 3 to 40 by 2
    set answer to answer + numerator / denominator
    
set numerator to numerator * factor
    
set denominator to denominator * i * (i - 1)
  end repeat
  
  
return answer
end sine_of

on cosine_of(x)
  return sine_of(x + 90)
end cosine_of

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2009/01/19 変数やサブルーチン名称に日本語を使用する

変数とサブルーチン名称、およびレコードの属性名については、前後をパーティカルバー(パイプ)記号で囲むことで、日本語の文字列が使えます。
(more…)

2009/01/11 pdfinfoの結果からポイント表記の数値をmmに書き換える

xpdf-toolsに含まれるpdfinfoを使ってPDFの情報を取得したあとに、サイズがポイント表記になっているものをmmに書き換えるサブルーチンです。汎用性も見るべきポイントもありませんが、まーこんなもんでしょう。
(more…)

2008/08/05 指定の数値リストを作成する

ループ内で、イレギュラーな処理をしたいような場合……たとえば、ループカウンタが奇数のときだけ処理を行いたいが、20のときにも例外的に処理を行いたい……といった場合、まあ普通はif文で条件分岐するわけですが、これが増えた場合には大変なことになります。
(more…)