@ポケじゃらし

音楽ゲームとかボーカロイドとか

【ExcelVBA】今日が何曜日か確認する【小ネタ】

どうも、じゃらしです。

最近本業でもテレワークが導入されて、毎日引きこもり生活をしている訳ですが、曜日感覚が分からなくなるんですよね。

そんな人は、VBEのイミディエイトウィンドウに下のコードを打ち込んでEnterを押すと、今日が何曜日か確認できます。

?WeekdayName(Weekday(Now))

オチはありません。

以上、それではまた。

【ExcelVBA】N-gramを実装してみた【言語処理】

どうも、じゃらしです。

今回はExcelVBAのネタです。

ExcelVBAで「言語処理100本ノック」に挑戦してみようと思い、N-gramというテキスト分割方法について実装してみました。
※「言語処理100本ノック」について気になる人はググってみて下さいませ

①文字単位のN-gramを行うクラスとして「CharNgram.cls」
②単語単位のN-gramを行うクラスとして「WordNgram.cls」
を作成します。

連想配列としてDictionary型を使用するので、事前に参照設定から
Microsoft Scripting Runtime」にチェックを付けておきましょう。

早速本題です。

'CharNgram.cls

Private N_ As Long

Public Property Let N(ByVal hoge As Long)
    N_ = hoge
End Property

Public Property Get N() As Long
    N = N_
End Property

Public Function ToNgram(ByRef hoge As String) As Dictionary
    Dim letters As String
    letters = Replace(hoge, " ", "")
    
    Dim length As Long
    length = Len(letters)
    
    Dim dic As New Dictionary
    Dim char As String
    
    Dim i As Long
    For i = 1 To length - N + 1
        char = Mid(letters, i, N)
        If Not dic.Exists(char) Then
            dic.Add char, char
        End If
    Next i
    
    Set ToNgram = dic
End Function

↑は、文字単位にN-gramを行う「CharNgram.cls」です。
使い方ですが、あらかじめNに数値を設定しておきます。
そして、N-gramしたい文章を引数としてToNgramを実行すると、N文字で分割された連想配列を返します。

'WordNgram.cls

Private N_ As Long

Public Property Let N(ByVal hoge As Long)
    N_ = hoge
End Property

Public Property Get N() As Long
    N = N_
End Property

Public Function ToNgram(ByRef hoge As String) As Dictionary
    Dim arrHoge() As String
    arrHoge = Split(hoge)
    
    Dim dic As New Dictionary
    Dim word As String
    
    Dim i As Long
    For i = LBound(arrHoge) To UBound(arrHoge) - N + 1
        word = ConcatWords(arrHoge, i)
        If Not dic.Exists(word) Then
            dic.Add word, word
        End If
    Next i
    
    Set ToNgram = dic
End Function

Private Function ConcatWords(ByRef arrHoge As Variant, ByVal index As Long) As String
    Dim arr() As String
    Dim i As Long
    For i = 1 To N
        ReDim Preserve arr(1 To i) As String
        arr(i) = arrHoge(index + i - 1)
    Next i
    ConcatWords = Join(arr)
End Function

↑は、単語単位にN-gramを行う「CharNgram.cls」です。
使い方は先ほどと同様、N-gramしたい文章を引数としてToNgramを実行すると、N単語で分割された連想配列を返します。

<実行例1>

'Module1.bas
Sub test()
    Dim sentence As String
    sentence = "I am an NLPer"
    With New CharNgram
        Dim i As Long
        For i = 1 To 3
            .N = i
            Debug.Print Join(.ToNgram(sentence).Items, ",")
        Next i
    End With
    
    With New WordNgram
        For i = 1 To 3
            .N = i
            Debug.Print Join(.ToNgram(sentence).Items, ",")
        Next i
    End With
End Sub

"I am an NLPer"という文章を文字・単語単位で分割して出力します。
Nが1~3の場合でそれぞれ分割しています。

f:id:twitpokej:20200415225933p:plain
Module1.test


<実行例2>

'Module2.bas
Sub test()
    Dim x As String, y As String
    x = "paraparaparadise"
    y = "paragraph"
    With New CharNgram
        .N = 2
        Debug.Print Join(.ToNgram(x).Items, ",")
        Debug.Print Join(.ToNgram(y).Items, ",")
    End With
End Sub

分割した要素は重複しないよ、という例です。

f:id:twitpokej:20200415230207p:plain
Module2.test

ExcelVBAでテキスト分析するかどうかはさておき、実装を考えるのは楽しかったです。(粉みかん)
以上、それではまた。

【ExcelVBA】複数選択しているシートのみを処理する

どうも、じゃらしです。

今回もExcelVBAの小ネタです。
シートタブをctrl+クリックで複数選択して、それらのシートだけに対して処理を行いたい時、たまにあるじゃないですか。

↓のコードで出来ます。

'Module1.bas
Sub test()
    Dim ws As Worksheet
    For Each ws In ActiveWindow.SelectedSheets
‘   シート毎に行いたい処理を記述する
        ws.Range(“A1”) = “ちくわ”
    Next
End Sub

以上、それではまた。

【ExcelVBA】結合演算子「&」と「+」

どうも、じゃらしです。
今回はExcelVBAの小ネタです。

ExcelVBAには、文字列結合を行う結合演算子が2つあります。
「&」と「+」です。

どちらも結合演算子としての機能は同じですが、加算か文字列結合かを明示するため、文字列結合する場合は「&」を使用するよう公式ヘルプでも推奨しているっぽいです。

以上、結合演算子は「&」を使いましょう〜

【ExcelVBA】クラスモジュールの使い方その1

どうも、じゃらしです。

今回もExcelVBAネタです。
VBAのクラスモジュールに関する記事です。

突然ですが、このコードを見たことがありますか?

Application.ScreenUpdating = False

ScreenUpdatingは、Excelの画面更新に関するApplicationのプロパティで、Falseにすると見かけ上画面描写されなくなります。
セルの値を操作するときは、これをFalseにしておくと次にTrueになる時まで見かけ上の画面描写を止めておくことができて、処理がまあまあ早くなります。

こんな感じで、マクロ実行時に必ず行わせたい処理があったりしますよね。

各プロシージャにScreenUpdating...をコーディングしていっても良いのですが、クラスモジュール化しておくと後々別のマクロでもインポートして使用したりできて便利なので紹介します。

実際のコード

今回は、パフォーマンス向上用クラスとして「PerformanceUp.cls」を作成します。

'PerformanceUp.cls

Private saved_ScreenUpdating As Long
Private saved_EnableEvents As Long

Private Sub Class_Initialize()
  With Application
    saved_ScreenUpdating = .ScreenUpdating
    saved_EnableEvents = .EnableEvents
    .ScreenUpdating = False
    .EnableEvents = False
  End With
  
End Sub

Private Sub Class_Terminate()
  With Application
    .ScreenUpdating = saved_ScreenUpdating
    .EnableEvents = saved_EnableEvents
  End With
  
End Sub

そして、PerformanceUpを標準モジュール上でインスタンス化します。

'Module1.bas

Sub test()
  Dim pu As PerformanceUp
  Set pu = New PerformanceUp
'以下処理を記述
  Debug.Print "ちくわ"
End Sub


こんな感じに記述すると、testプロシージャ実行時にPerformanceUpのClass_Initializeが呼び出されます。
そして、End Sub時にPerformanceUpのClass_Terminateが呼び出されます。

Application.ScreenUpdatingは画面更新
Application.EnableEventsはシート削除時などのダイアログ有無
ここら辺は切っちゃうことが多いので、WithでApplicationを括って記述しています。

特別なプロシージャ

Class_Initialize:コンストラク
Class_Terminate:デストラク
これらのプロシージャは特別で、コンストラクタはそのクラスがNewされる時(インスタンス生成時)に自動的に呼び出されます。
また、デストラクタはNewされたインスタンスがどこからも参照されなくなった時に自動的に呼び出されます。


注意1
Dim pu As New PerformanceUp

上記のようにpu宣言時にインスタンスを生成する書き方もありますが、この場合Class_Initializeは「次にpuが参照されるタイミング」で呼び出されます。つまり、Class_Initializeが呼び出されるか分からなくなってしまいます。
このクラスはプロシージャ開始時にいろいろ設定したりするのが目的ですので、この書き方は避けるべきです。

注意2
Set pu = Nothing

と記述することで、任意のタイミングでインスタンスを破棄させてClass_Terminateを呼び出すこともできます。

以上、それではまた。

【ExcelVBA】FileDialogを活用してファイル操作をもっと便利に

どうも、じゃらしです。

今回もExcelVBAネタです。

以前取り上げた「FileSystemObject」に関連する内容です。
twitpokej.hatenablog.com
twitpokej.hatenablog.com

ファイルのパスを指定する際、変数にパスを直接コーディングしていました。
ですが、ファイルダイアログで指定できたらいいのに、と思う場面ありませんか。(こんなの↓)
f:id:twitpokej:20200205003150p:plain

そんな時は、ExcelVBAの「FileDialog」を使うことで実現できます。

以下サンプルコード

Sub test()
  Dim fso As New FileSystemObject
  
  'ファイルダイアログを表示する
  With Application.FileDialog(msoFileDialogFilePicker)
  
    If .Show Then
      Dim hoge As Variant
      
      '選択したファイル1つ1つに対して処理を行う
      For Each hoge In .SelectedItems
        Debug.Print fso.GetFile(hoge).Name
      Next
    End If
  End With
  
End Sub

ファイル選択中
f:id:twitpokej:20200205003439p:plain

実行結果
f:id:twitpokej:20200205003529p:plain

選択したファイル名を表示してくれます。

ちなみに、ファイルダイアログ上で複数選択した場合にも対応しています。
「FileDialog」で選択したアイテムのパスが配列「SelectedItems」に格納されているので、For Each文を使えば1つ1つに対して処理を行うこともできます。

複数ファイル選択中
f:id:twitpokej:20200205004227p:plain

実行結果
f:id:twitpokej:20200205004245p:plain

以上、それではまた。

ヴィクトリー・ドラゴンに攻撃されたら肘鉄で山札を崩せ

効果モンスター(禁止カード)
星8/闇属性/ドラゴン族/攻2400/守3000
このカードは特殊召喚できない。
自分フィールド上のドラゴン族モンスター3体を
生け贄にして生け贄召喚しなければならない。
このカードの直接攻撃によって相手ライフを0にした場合、
このカードのコントローラーはマッチに勝利する。

――遊戯王wikiより引用

あなたは罰則規定によりデュエルには敗北しますが、マッチキルから逃げられます。


こんにちは、じゃらしです。

今回は、対戦ゲームの愚痴を書きました。

遊戯王には、ヴィクトリー・ドラゴン以外にもマインドクラッシュの件やら、ありますよね。

ルール上ありなので、まあ狙えるなら狙っちゃうよね、という感じです。
でも、もやもやーっとしますよね。しません?

以上、それではまた。