'文字の出現頻度を数える #Include Once "fb-dictionary-src.bi" #Include Once "fb-dict-reference.bas" #Include "window9.bi" /' ****************************************** 文字の出現頻度を数える ****************************************** このプログラムは paul doe さんの下記プログラムをベースに修正したものです。 https://www.freebasic.net/forum/viewtopic.php?f=7&p=247578&sid=1e219112395b8599409f858ab0d58029#p247578 Dictionary Class by paul doe ≫ May 20, 2018 16:05 '変数変更 ' name = pName→ Character = pCharacter ' address = pAddress→削除 ' age = pAge CountsOfCharacter = pCountsOfCharacter ' RegisterDictionary →RecordDictionary このコードは、Dictionaryクラスの使用例を示しています。 複合型('database register' のように Register と呼ぶ)を定義し、 この型に特定の辞書を継承します。 また、この辞書に新しい登録を追加するので、 インスタンス削除時に、基本クラスのガベージコレクション機能を使って 登録を破棄します。 '/ /' 複合型を定義します。複合型の全メンバーを公開します。 これは、アプリが処理する 'データ'を表します。 '/ Type Record Public: Declare Constructor() Declare Constructor( _ ByRef As Const String, ByVal As Integer ) Declare Destructor() As String Character As Integer CountsOfCharacter End Type Constructor Record() Character = "Unknown" CountsOfCharacter = 0 End Constructor Constructor Record( _ ByRef pCharacter As Const String, ByVal pCountsOfCharacter As Integer ) Character = pCharacter CountsOfCharacter = pCountsOfCharacter End Constructor Destructor Record() End Destructor /' レコードを処理するための辞書実装 '/ Type RecordDictionary extends Dictionary Public: Declare Constructor() Declare Destructor() Declare Function Add( ByRef As Const String, ByVal As Record Ptr ) As boolean Declare Function item( ByRef As Const String ) As Record Ptr Declare Sub remove( ByRef As Const String ) Declare Function keyExists( ByRef As Const String ) As boolean End Type Constructor RecordDictionary() base() End Constructor Destructor RecordDictionary() End Destructor Function RecordDictionary.add( _ ByRef key As Const String, ByVal value As Record Ptr ) As boolean /' 廃棄コールバックを指定しないことに注意してください。 これは、* index *データではなく、* store *データにしたいだけです。 これは実際にこのクラスの元の意図です (廃棄コールバックは、集中管理されたデータ管理メカニズムがない場合に備えられています)。 '/ Return( base.add( key, value ) ) End Function Sub RecordDictionary.remove( ByRef key As Const String ) base.remove( key ) End Sub Function RecordDictionary.item( ByRef key As Const String ) As Record Ptr Return( Cast( Record Ptr, base.item( key ) ) ) End Function Function RecordDictionary.keyExists( ByRef key As Const String ) As boolean Return( base.keyExists( key ) ) End Function '' レコードの配列を文字の出現頻度順にソートする Sub sortArray( ByVal startIndex As Integer, ByVal endIndex As Integer, array() As Record Ptr ) Dim As Integer firstHalf, secondHalf Dim As Integer pivot firstHalf = startIndex secondHalf = endIndex '' Use the median value as pivot pivot = array( ( firstHalf + secondHalf ) \ 2 )->CountsOfCharacter Do '' Find < pivot Do While( array( firstHalf )->CountsOfCharacter < pivot ) firstHalf = firstHalf + 1 Loop '' Find > pivot Do While( array( secondHalf )->CountsOfCharacter > pivot ) secondHalf = secondHalf - 1 Loop '' Swap if needed If( firstHalf <= secondHalf ) Then Swap array( firstHalf ), array( secondHalf ) firstHalf = firstHalf + 1 secondHalf = secondHalf - 1 End If Loop Until( firstHalf > secondHalf ) '' Repeate sort until each half is sorted If( secondHalf > startIndex ) Then sortArray( startIndex, secondHalf, array() ) End If If( firstHalf < endIndex ) Then sortArray( firstHalf, endIndex, array() ) End If End Sub /' ★★★★★★★★★★★★ 辞書の使用例 '/ '' 文字と頻度の辞書を作成する '★CharacterIndexを作成★ ''キーでデータをインデックス化するための辞書を作成する Dim As RecordDictionary Ptr dic = New RecordDictionary() '' ソート用の配列を作る Dim As Record Ptr Records( 0 To 100 ) Dim INPUTFILE As HANDLE 'ファイルのハンドル Dim FullPass As String '対象ファイルのフルパス Dim Filehandle As Integer Dim StringVariable As String Dim CountsOfCharacter As Integer Dim CountsOfLine As Integer Dim TotalCountOfCharacters As Integer Dim CharacterSymbol As String Dim Position As Integer Dim Counter As Integer Dim NumberOfCharacterTypes As Integer Dim Number As Integer Counter = -1 '調べたい文字列を含むファイルを入力する '********************* Window9 のファイルを開くダイアログを使う ********************* FullPass = OpenFileRequester("Specify English text file",ExePath,"Text File(*.txt;*.csv;*.htm*)"_ +Chr(0)+"*.txt;*.csv;*.htm*"+Chr(0)+"All File(*.*)"+Chr(0)+"*.*"+Chr(0)) If FullPass<>"" Then '' 入力のテキストのファイルを開きます。 INPUTFILE = Read_File(FullPass) If INPUTFILE <> -1 Then 'ファイルが開いたことを確認します Close_File(INPUTFILE) EndIf ' テキストファイルの内容読み込み処理 CountsOfLine = 0 TotalCountOfCharacters = 0 Filehandle = FreeFile Open FullPass For Input As #Filehandle 'テキストファイルのオープン If Lof(Filehandle) > 0 Then Do Until EOF(Filehandle ) Line Input #Filehandle, StringVariable '1行読み込み StringVariable = Trim(StringVariable) CountsOfLine = Len(StringVariable) TotalCountOfCharacters = TotalCountOfCharacters + CountsOfLine If CountsOfLine >0 Then ? ? "CountsOfLine = " , CountsOfLine ? "TotalCountOfCharacters = ", TotalCountOfCharacters ? "StringVariable = " , StringVariable ? For Position = 1 To CountsOfLine CharacterSymbol = Mid(StringVariable, Position, 1) If Trim(CharacterSymbol) <> "" Then '' 'keyExists' メソッドを使ってキーが存在するかどうかを確認します。 If( dic->keyExists(CharacterSymbol) = TRUE ) Then '既存の場合は文字の出現頻度を追加します Number = dic->item(CharacterSymbol)->CountsOfCharacter Number = Number + 1 '? CharacterSymbol; '? Number; '? " "; dic->item(CharacterSymbol)->CountsOfCharacter = Number Else ' この文字は辞書に登録されていません。辞書に追加します。 Counter =Counter +1 '? Counter ; '? CharacterSymbol ; dic->Add( CharacterSymbol, New Record( CharacterSymbol, 1 ) ) Records( Counter ) = New Record( CharacterSymbol, 1 ) End If End If Next Position End If Loop Else GoTo HandleErrors End If Close #Filehandle 'ファイル番号を通したファイルを閉じます。 Else MessBox("メッセージ","ファイルが選択されませんでした!") End EndIf '配列の出現頻度を更新する NumberOfCharacterTypes = Counter For Counter = 0 To NumberOfCharacterTypes CharacterSymbol = records( Counter )->Character Number = dic->item(CharacterSymbol)->CountsOfCharacter Records( Counter ) = New Record(CharacterSymbol ,Number ) Next ? ? "入力を終了しました。何かキー入力で継続します。" ? Sleep() For Counter = 0 To NumberOfCharacterTypes ? records( Counter )->Character ; ? records( Counter )->CountsOfCharacter; ? " " ; Next ? ? "ソート用の配列を更新しました。何かキー入力でソートを開始します。", NumberOfCharacterTypes ,UBound( records ) ? Sleep() '' レコードの配列をソートする sortArray( 0, NumberOfCharacterTypes, records() ) ''文字の出現頻度順に出現数と文字を表示します For Counter= 0 To NumberOfCharacterTypes ? records( Counter )->Character ; ? records( Counter )->CountsOfCharacter Next ' 入力ファイルの総文字数 ? "TotalCountOfCharacters = " & TotalCountOfCharacters ? ? "文字の出現頻度順に文字と出現数を表示しました。何かキー入力でプログラムを終了します。" Sleep() '' Cleanup For Counter = 0 To UBound( Records ) Delete( Records( Counter ) ) Next Delete( dic ) End HandleErrors: Print "File not found" Sleep