| — Created 2019-06-29 by Takaaki Naganoya — 2019 Piyomaru Software
 use AppleScript version "2.5"
 use scripting additions
 use framework "Foundation"
 use framework "AppKit"
 use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html
property NSView : a reference to current application’s NSView
 property NSAlert : a reference to current application’s NSAlert
 property NSColor : a reference to current application’s NSColor
 property NSTextField : a reference to current application’s NSTextField
 property NSTextView : a reference to current application’s NSTextView
 property NSScrollView : a reference to current application’s NSScrollView
 property NSRunningApplication : a reference to current application’s NSRunningApplication
–property theResult : 0
 property returnCode : 0
 property segRes : missing value
set segRes to missing value
tell application "CotEditor"
 if (count every document) = 0 then return –No Document
 
 tell front document
 set aText to contents of it
 set lineTerm to (line ending)
 end tell
 
 –改行コードの選択(ドキュメントの状態から取得)
 if lineTerm = LF then
 set aRet to ASCII character 10 –To avoid keyword conflict (string)
 else if lineTerm = CR then
 set aRet to ASCII character 13
 else if lineTerm = CRLF then
 set aRet to (ASCII character 13) & (ASCII character 10)
 else
 set aRet to ASCII character 10
 end if
 end tell
–事前にテキストから自動で数値部分を抽出して分析
 set cArray to extractNumberFromText(aText) of me
 set aRes to (cArray’s valueForKeyPath:"@max.self")’s intValue()
 set bRes to (cArray’s valueForKeyPath:"@min.self")’s intValue()
 set cRes to (cArray’s valueForKeyPath:"@count")’s intValue()
–事前に数字の分布シミュレーションを計算
 set tmpLen to count every character of (aRes as string)
 set theList to my findPattern:("[0-9]{" & tmpLen & "}") inString:aText
 set sampleStr to calculateNumFreq(cArray, "■", aRet, bRes, aRes, true) of me
set sampleStr to return & return & "テスト集計結果:" & return & return & sampleStr
–テキストからの数値抽出時のパラメータ取得
 set paramObj to {myMessage:"テキスト内の数値の度数分布集計", mySubMessage:"集計対象の数値の範囲と、集計時のグラフ生成時の構成文字を指定してください", mes1:"最小値(min.)", mes1Default:(bRes as string), mes2:"最大値(max.)", mes2Default:(aRes as string), mes3:"出力文字", mes3Default:"絆", aSample:sampleStr}
–set segRes to my inputParametersFromAlertDialog:paramObj–for debugging
 my performSelectorOnMainThread:"inputParametersFromAlertDialog:" withObject:(paramObj) waitUntilDone:true
 if segRes = missing value then return –Cancel
–度数分布計算
 set tmpLen to count every character of ((a2Res of segRes) as string)
 set theList to my findPattern:("[0-9]{" & tmpLen & "}") inString:aText
 set outStr to calculateNumFreq(cArray, a3Res of segRes, aRet, a1Res of segRes, a2Res of segRes, false) of me
–テキストエディタへの集計結果出力
 tell application "CotEditor"
 tell front document
 set contents of it to (aText & aRet & aRet & "集計結果:" & aRet & aRet & outStr & aRet)
 end tell
 end tell
on inputParametersFromAlertDialog:paramObj
 –Receive Parameters
 set aMainMes to (myMessage of paramObj) as string –Main Message
 set aSubMes to (mySubMessage of paramObj) as string –Sub Message
 set mes1Label to (mes1 of paramObj) as string –Text Input field 1 Label
 set mes2Label to (mes2 of paramObj) as string –Text Input field 2 Label
 set mes3Label to (mes3 of paramObj) as string –Text Input field 3 Label
 set aTextInputString to (mes1Default of paramObj) as string –Text Input field 1 Default value
 set bTextInputString to (mes2Default of paramObj) as string –Text Input field 2 Default value
 set cTextInputString to (mes3Default of paramObj) as string –Text Input field 2 Default value
 set sampleString to (aSample of paramObj) as string
 
 — Create a view
 set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 500, 400))
 
 — create two input field and their labels pairs
 –NSTextFields for Input
 set aTextInput to makeNSTextField(100, 70, 140, 20, true, (aTextInputString), true, true) of me
 set bTextInput to makeNSTextField(100, 35, 140, 20, true, (bTextInputString), true, true) of me
 set cTextInput to makeNSTextField(100, 0, 140, 20, true, (cTextInputString), true, true) of me
 
 –Labels
 set a1TF to makeNSTextField(0, 70, 100, 20, false, (mes1Label), false, false) of me
 set a2TF to makeNSTextField(0, 35, 100, 20, false, (mes2Label), false, false) of me
 set a3TF to makeNSTextField(0, 0, 100, 20, false, (mes3Label), false, false) of me
 
 –Sample Text View
 set aColor to NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.9
 set tvScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 120, 500, 300))
 set tvView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 120, 500, 380))
 tvView’s setRichText:true
 tvView’s useAllLigatures:true
 tvView’s setTextColor:(NSColor’s cyanColor()) —
 tvView’s setFont:(current application’s NSFont’s fontWithName:"HiraginoSans-W1" |size|:16.0)
 tvView’s setBackgroundColor:aColor
 tvView’s setEditable:false
 
 tvScroll’s setDocumentView:tvView
 tvView’s enclosingScrollView()’s setHasVerticalScroller:true
 tvView’s setString:(sampleString)
 
 
 theView’s setSubviews:{a1TF, aTextInput, a2TF, bTextInput, a3TF, cTextInput, tvScroll}
 
 — set up alert
 set theAlert to NSAlert’s alloc()’s init()
 tell theAlert
 its setMessageText:aMainMes
 its setInformativeText:aSubMes
 its addButtonWithTitle:"OK"
 its addButtonWithTitle:"Cancel"
 its setAccessoryView:theView
 end tell
 
 — show alert in modal loop
 NSRunningApplication’s currentApplication()’s activateWithOptions:0
 my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
 if (my returnCode as number) = 1001 then
 set my segRes to missing value
 else
 set s1Val to (aTextInput’s integerValue()) as integer
 set s2Val to (bTextInput’s integerValue()) as integer
 set s3Val to (cTextInput’s stringValue()) as string
 
 –return {a1Res:s1Val, a2Res:s2Val, a3Res:s3Val}–old version’s way to return values
 set my segRes to {a1Res:s1Val, a2Res:s2Val, a3Res:s3Val}
 end if
 end inputParametersFromAlertDialog:
on doModal:aParam
 set (my returnCode) to aParam’s runModal()
 end doModal:
on makeNSTextField(xPos as integer, yPos as integer, myWidth as integer, myHeight as integer, editableF as boolean, setVal as string, backgroundF as boolean, borderedF as boolean)
 set aNSString to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, yPos, myWidth, myHeight))
 aNSString’s setEditable:(editableF)
 aNSString’s setStringValue:(setVal)
 aNSString’s setDrawsBackground:(backgroundF)
 aNSString’s setBordered:(borderedF)
 return aNSString
 end makeNSTextField
–与えられたテキストから数値部分を抽出して1D Arrayで返す
 on extractNumberFromText(aText)
 set aStr to current application’s NSString’s stringWithString:aText
 –set nonDigitCharacterSet to (current application’s NSCharacterSet’s decimalDigitCharacterSet())’s invertedSet()
 set nonDigitCharacterSet to (current application’s NSCharacterSet’s characterSetWithCharactersInString:"0123456789.,")’s invertedSet()
 set bArray to (aStr’s componentsSeparatedByCharactersInSet:nonDigitCharacterSet)
 
 –Sweep Blank Items
 load framework –BridgePlus
 set cArray to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bArray))’s valueForKey:"intValue"
 return cArray –return as NSArray
 end extractNumberFromText
–正規表現でテキスト中から指定パターンに該当する箇所を抽出してリストで返す
 on findPattern:thePattern inString:theString
 set theOptions to ((current application’s NSRegularExpressionDotMatchesLineSeparators) as integer) + ((current application’s NSRegularExpressionAnchorsMatchLines) as integer)
 set theRegEx to current application’s NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
 set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
 set theFinds to theFinds as list — so we can loop through
 set theResult to {} — we will add to this
 set theNSString to current application’s NSString’s stringWithString:theString
 repeat with i from 1 to count of items of theFinds
 set theRange to (item i of theFinds)’s range()
 set end of theResult to (theNSString’s substringWithRange:theRange) as integer
 end repeat
 return theResult
 end findPattern:inString:
–1D Listをユニーク化してソート
 on uniquifyAndSort1DList(theList as list, aBool as boolean)
 set aArray to current application’s NSArray’s arrayWithArray:theList
 set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
 set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
 set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
 
 set bList to cArray as list
 return bList
 end uniquifyAndSort1DList
–度数分布集計して文字グラフ出力
 on calculateNumFreq(theList, outChar, aLineTerminator, aMin, aMax, zeroPaddingF)
 set theCountedSet to current application’s NSCountedSet’s alloc()’s initWithArray:theList
 set newArray to current application’s NSMutableArray’s new()
 
 set kList to uniquifyAndSort1DList(theList, false) of me –降順ソート
 set maxDigit to (count every character of (aMax as string))
 
 repeat with i in kList
 if (i ≥ aMin) and (i ≤ aMax) then
 (newArray’s addObject:{theKey:i, theCount:(theCountedSet’s countForObject:i)})
 end if
 end repeat
 
 set outStr to ""
 
 repeat with i in newArray as list
 set j to (current application’s NSDictionary’s dictionaryWithDictionary:i)
 set tmpStr to (j’s valueForKey:"theKey")
 
 if zeroPaddingF = true then
 –Zero Pagging
 set keyNumStr to numToZeroPaddingStr(tmpStr, maxDigit, "0") of me
 else
 –No Padding
 copy (tmpStr as string) to keyNumStr
 end if
 
 set outStr to outStr & keyNumStr & ":"
 
 set aNum to (j’s valueForKey:"theCount")
 repeat aNum times
 set outStr to outStr & outChar
 end repeat
 
 set outStr to outStr & aLineTerminator
 end repeat
 end calculateNumFreq
–整数の値に指定桁数ゼロパディングして文字列で返す
 on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
 set aNumForm to current application’s NSNumberFormatter’s alloc()’s init()
 aNumForm’s setPaddingPosition:(current application’s NSNumberFormatterPadBeforePrefix)
 aNumForm’s setPaddingCharacter:paddingChar
 aNumForm’s setMinimumIntegerDigits:aDigit
 
 set bNum to current application’s NSNumber’s numberWithInt:aNum
 set aStr to aNumForm’s stringFromNumber:bNum
 
 return aStr as text
 end numToZeroPaddingStr
 |