[PYTHON] [201911 ~ 201912] Recently created miscellaneous programs and tools, etc.

About this article

Miscellaneous programs and tools I recently made for personal use.

--Small and simple articles that are not enough to stand individually. --Language is Python, Powershell, Excel VBA. --The usage environment is - Windows10。 - Powershell5.1。 - Python3.7.0。 - Office2016。

Since the article is long, it may be better to jump only the items you want to see from the table of contents.
* The latest tools and source code are available on GitHub.

https://github.com/dede-20191130/CreateToolAndTest

1.Python

1-1. A program that puts old or old or named folders into the trash can with the files directly under it.

Trigger

If you don't consciously organize folders with names like old, they will be stored forever. I wanted to declutter.

code

Crean_OldNamed_Folders.py


import glob
import os
import tkinter as tk
import tkinter.simpledialog as sim
from tkinter import messagebox
import send2trash


def Main():
    root = tk.Tk()
    root.withdraw()
    tmpPath = sim.askstring("old folder search folder specification", "Please specify the folder path to search the old folder", initialvalue="")
    if tmpPath not in (None, ''):
        ThrowAwayOld(tmpPath)


def ThrowAwayOld(baseFolderPath):
    """Recursively search for old folders and send their contents to the trash"""
    if not os.path.isdir(baseFolderPath):
        messagebox.showerror("error", "A folder path that does not exist.")
        exit(1)

    rmNum = 0
    for f in glob.glob(baseFolderPath + '\\**', recursive=True):
        if os.path.isdir(f) and os.path.basename(f).lower() in ('old', 'old', 'Old'):
            send2trash.send2trash(os.path.abspath(f))
            rmNum += 1

    messagebox.showinfo("Successful completion", "The process is complete.\n" + str(rmNum) + "I sent the old folders to the Trash.")


if __name__ == '__main__':
    Main()

Commentary

    for f in glob.glob(baseFolderPath + '\\**', recursive=True):
        if os.path.isdir(f) and os.path.basename(f).lower() in ('old', 'old', 'Old'):
            send2trash.send2trash(os.path.abspath(f))
            rmNum += 1

Recursive file search is possible by setting recursive in the glob.glob function.

Send the folder containing words such as "old" and "old" to the trash.

I wanted to put a cushion in the form of sending it to the trash can because it cannot be restored when it is removed.

1-2. A program that changes only a specific file path character string in the text to a general-purpose one

Trigger

When publishing the source code to SNS such as Qiita, I somehow didn't want to include my personal file path or filename. Therefore, I created a program that can replace file paths at once.

Source code

ChangePrivatePathsOfText.py


import os
import pathlib
import re
import chardet


def Main():
    with pathlib.Path(os.getenv("HOMEDRIVE") + os.getenv(
            "HOMEPATH") + r'\PycharmProjects\CreateToolAndTest\PrivateTool\ChangedString.txt') as pp:
        #Detect character code
        with open(pp.absolute(), "rb") as f:
            temp = chardet.detect(f.read())['encoding']

        #Input characters
        allText = pp.read_text(encoding=temp)


        # ///Regular expression replacement
        #File path replacement
        allText = re.sub(r'"[a-zA-Z]:[\\/].*\.', r'"C:/Users/UserName/MyFolder/Foo.', allText)
        allText = re.sub(r"'[a-zA-Z]:[\\/].*\.", r"'C:/Users/UserName/MyFolder/Foo.", allText)
        #Replace folder path
        allText = re.sub(r'"[a-zA-Z]:[\\/](?!.*\.).*"',r'"C:/Users/UserName/MyFolder/Foo."',allText)
        allText = re.sub(r"'[a-zA-Z]:[\\/](?!.*\.).*'",r"'C:/Users/UserName/MyFolder/Foo.'",allText)

        #Output after replacement
        pp.write_text(allText, encoding=temp)


if __name__ == '__main__':
    Main()

Commentary

Using the read_text / write_text functions and with syntax of the pathlib module File input / output is simplified.

        #Detect character code
        with open(pp.absolute(), "rb") as f:
            temp = chardet.detect(f.read())['encoding']

        #Input characters
        allText = pp.read_text(encoding=temp)

The entire character string is read using the character code detected in advance.

        # ///Regular expression replacement
        #File path replacement
        allText = re.sub(r'"[a-zA-Z]:[\\/].*\.', r'"C:/Users/UserName/MyFolder/Foo.', allText)
        allText = re.sub(r"'[a-zA-Z]:[\\/].*\.", r"'C:/Users/UserName/MyFolder/Foo.", allText)
        #Replace folder path
        allText = re.sub(r'"[a-zA-Z]:[\\/](?!.*\.).*"',r'"C:/Users/UserName/MyFolder/Foo."',allText)
        allText = re.sub(r"'[a-zA-Z]:[\\/](?!.*\.).*'",r"'C:/Users/UserName/MyFolder/Foo.'",allText)

Regarding the file path,

--First starts with "" "or"'" --Next comes the alpha bed character +: + (either \ or /) --Finally, "." Comes

Regular expression substitution is used under the condition.

Regarding the folder path,

--First starts with "" "or"'" --Next comes the alpha bed character +: + (either \ or /) --Does not include "." Characters after that --Ends with "" "or"'"

Regular expression substitution is used under the condition.

1-3. A program that changes only a specific URL character string in the text to a general-purpose one

Trigger

Almost the same as 1-2

Source code

ChangeURLPartsOfText.py


import os
import pathlib
import re
import chardet


def Main():
    with pathlib.Path(os.getenv("HOMEDRIVE") + os.getenv(
            "HOMEPATH") + r'\PycharmProjects\CreateToolAndTest\PrivateTool\ChangedString.txt') as pp:
        #Detect character code
        with open(pp.absolute(), "rb") as f:
            temp = chardet.detect(f.read())['encoding']

        #Input characters
        allText = pp.read_text(encoding=temp)
        # print(allText)

        #Regular expression replacement
        allText = re.sub(r'"https?://.*"', r'"http://foobar.com"', allText)
        allText = re.sub(r"'https?://.*'", r"'http://foobar.com'", allText)

        #Output after replacement
        pp.write_text(allText, encoding=temp)


if __name__ == '__main__':
    Main()

Commentary

        #Regular expression replacement
        allText = re.sub(r'"https?://.*"', r'"http://foobar.com"', allText)
        allText = re.sub(r"'https?://.*'", r"'http://foobar.com'", allText)

It supports character strings enclosed in both single quotes and double quotes.

1-4. Homebrew class: Simplified display of tkinter message box

Trigger

The message box display of python is Since various preparations such as setting the root frame are troublesome I wanted to be able to display a message with a single call to a static method.

Source code

TkHandler_MsgBox_1.py


import tkinter as tk
from tkinter import messagebox


class TkHandler_MsgBox_1:
    """
Message box handling class_1
    """

    def __init__(self):
        self.root = tk.Tk()
        self.root.withdraw()

    def __del__(self):
        self.root.destroy()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    def normalMsgBox(self, title='message', content='ここにmessageが表示されます。'):
        messagebox.showinfo(title, content)

    def errorMsgBox(self, title='error', content='errorが発生しました。'):
        messagebox.showerror(title, content)

    @staticmethod
    def showStandardMessage(title, content, isError=False, errorTitle=None, errorContent=None):
        """
Used when displaying a message in standard usage.
Release the Tk object immediately without reusing it.

        :arg
            (error)title:(error)title
            (error)content:(error)Message content
            isError:If an error occurs, an error message will be displayed.

        """
        with TkHandler_MsgBox_1() as objMsg:
            myTitle = title if not isError else errorTitle
            myContent = content if not isError else errorContent
            calledFunc = objMsg.normalMsgBox if not isError else objMsg.errorMsgBox

            calledFunc(title=myTitle, content=myContent)

Commentary

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

The above is the context manager when using the with syntax. Reference: https://python.keicode.com/lang/context-manager.php

I will not do anything this time.

    def normalMsgBox(self, title='message', content='ここにmessageが表示されます。'):
        messagebox.showinfo(title, content)

    def errorMsgBox(self, title='error', content='errorが発生しました。'):
        messagebox.showerror(title, content)

When each is called, a message is displayed under the conditions set in the argument. This time, only the functions corresponding to the information message and error message are implemented.

            myTitle = title if not isError else errorTitle
            myContent = content if not isError else errorContent
            calledFunc = objMsg.normalMsgBox if not isError else objMsg.errorMsgBox

            calledFunc(title=myTitle, content=myContent)

Conditionally branch a variable with a ternary operator according to the value of isError.

The final function calledFunc will be either normalMsgBox or errorMsgBox.

how to use

Use it like this. It can be called in one line without the need to set the root frame.

from Commons.TkHandler_MsgBox_1 import TkHandler_MsgBox_1
 TkHandler_MsgBox_1.showStandardMessage('Processing completed', 'The file move is complete.')

1-5. A program that copies files in a specified folder to different folders.

Trigger

Photos taken with a smartphone etc. I wanted to move it to both the pictures on my PC and the G drive folder.

Source code

CopyPicsToFolders.py


import glob
import os
import sys

#Reset module search path
#Make it possible to start by double-clicking
sys.path.append(os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + r"\PycharmProjects\CreateToolAndTest")
import shutil
import send2trash
# Common parts in dede-20191130's GitHub
# https://github.com/dede-20191130/CreateToolAndTest
from Commons.TkHandler_MsgBox_1 import TkHandler_MsgBox_1


def Main():
    isSuccess = True

    try:
        mySrcPath = r'C:/Users/UserName/MyFolder/Foo'
        myDestpathList = [r'C:/Users/UserName/MyFolder/Bar', r'C:/Users/UserName/MyFolder/Dede']
        movedFileList = []

        #Get all image files directly under the specified folder
        if os.path.isdir(mySrcPath):
            for file in glob.glob(mySrcPath + '\\*', recursive=False):
                if os.path.isfile(file):
                    movedFileList.append(file)
        else:
            print('No Directory')
            exit(0)

        #Copy to specified output destination folder
        for dst in myDestpathList:
            [shutil.copy(os.path.abspath(file2), dst) for file2 in movedFileList]
    except:
        isSuccess = False

    finally:
        if isSuccess:
            TkHandler_MsgBox_1.showStandardMessage('Processing completed', 'The file move is complete.')
            for file in glob.glob(mySrcPath + '\\*', recursive=False):
                send2trash.send2trash(os.path.abspath(file))


if __name__ == '__main__':
    Main()

Commentary

    except:
        isSuccess = False

    finally:
        if isSuccess:
            TkHandler_MsgBox_1.showStandardMessage('Processing completed', 'The file move is complete.')
            for file in glob.glob(mySrcPath + '\\*', recursive=False):
                send2trash.send2trash(os.path.abspath(file))

If you don't catch the exception Display a message assuming that it is a normal judgment, Send the files in the original folder to the Trash.

1-6. Dice tool to get random integers without using random module

Trigger

If you get the time at the nanosecond level Is it possible to get random numbers at the human experience level? I made it.

Source code

DiceAppWithoutRandomLibrary.py


import time
import tkinter as tk
from tkinter import messagebox


def diceResult():
    #Random variable acquisition depending on the time (in human experience time)
    temp = int((time.time_ns() % 100000000) / 100)
    #Get the remainder divided by 6
    myTempRmd = temp % 6
    if myTempRmd == 0:
        myTempRmd = 6

    return myTempRmd


if __name__ == '__main__':
    #Get dice results
    result = diceResult()
    #Displayed as a message as a result of rolling the dice
    root = tk.Tk()
    root.withdraw()  #Don't show small windows
    messagebox.showinfo("Dice", "The result is" + str(result) + "is")

Commentary

2.Powershell

2-1. Script to hibernate after a specified second

Trigger

before sleep, When I try to sleep after transferring files to G drive You have to wait for the transfer to complete. I created a script to put it to sleep after some time (after the transfer is complete).

Source code

hibernationTimer.ps1


Param(
    [long]$waitTime = 300   #Wait time (s)
    )

sleep $waitTime 
#Hibernate
shutdown -h

#Close only the console window that executed this script (PID is an automatic variable that sets the process ID of the running PowerShell)
Stop-Process -Id $PID

Commentary

Specify the number of seconds specified in the argument (default is 300 seconds) Run on the console.

Automatically closes the console screen when entering hibernation.

2-2. Script that starts WinMerge with the two folders that you always use compared

Trigger

If you can start with the folders that you always compare (old and new project folders, etc.) compared Created thinking that it is not necessary to specify it on the folder specification screen each time.

Method

Add the following to the Powershell profile file.

powershell:Microsoft.PowerShellISE_profile.ps1


Sal wmg C:\Tool_nonInstall\winmerge-2.16.4-x64-exe\WinMerge\WinMergeU.exe
function wtmp() {
    wmg $HOME\Documents\Dif_1 $HOME\Documents\Dif_2
}

Commentary

When you run "wtmp" on the console Start WinMerge with Dif_1 and Dif_2 compared.

3.ExcelVBA

3-1. Tool to format Excel book

Trigger

When handing an Excel book to the other party The sheet is the leftmost sheet, Some people complain that the cursor isn't pointing to cell A1.

A tool to prevent such people from saying anything.

Source code

tool


'******************************************************************************************
'*Function name: formatForSubmission
'*Function: You can do it quickly when you need to arrange the appearance when submitting an Excel book to the other party.
'Move the cursor of all sheets to the upper left cell (A1 cell) and make the leftmost sheet active.
'*argument(1):None
'******************************************************************************************
Public Sub formatForSubmission()
    
    'constant
    Const FUNC_NAME As String = "formatForSubmission"
    
    'variable
    Dim cntObj As Object                         'Loop counter
    
    On Error GoTo ErrorHandler
    '---Describe the process below---
    
    'Move the cursor of all sheets to the upper left cell (A1 cell)
    For Each cntObj In Worksheets
        'Skip hidden cells
        If cntObj.Visible = True Then
            cntObj.Select
            cntObj.Range("A1").Select
        End If
    Next
    
    'Select the lowest numbered visible sheet
    For Each cntObj In Worksheets
        If cntObj.Visible = True Then
            cntObj.Select
            Exit For
        End If
    Next
    

ExitHandler:

    Exit Sub
    
ErrorHandler:

    MsgBox "An error has occurred, so exit" & _
           vbLf & _
           "Function name:" & FUNC_NAME & _
           vbLf & _
           "Error number" & Err.Number & Chr(13) & Err.Description, vbCritical
        
    GoTo ExitHandler
        
End Sub

3-2. Tool to insert a string before or after the value of all cells in the selected range

Trigger

When creating markdown text Insert quotation marks ">" and strikethrough decoration "(before and after sentences) ~" I wanted a tool that would make it easy.

Source code

tool


'For a particular object or value
'Represents the position to perform function processing
Public Enum ProcessingPosition
    Front = 1
    Back = 2
    Both = 3
End Enum

'******************************************************************************************
'*Function name: insertStrToSelection
'*Function: Inserts a character string at the specified position of the value of all cells in the selected range.
'*Designated position: Front / rear or both front and back
'*argument(1):None
'******************************************************************************************
Public Sub insertStrToSelection()
    
    'constant
    Const FUNC_NAME As String = "insertStrToSelection"
    
    'variable
    Dim insertedStr As String
    Dim insertPosition As Long
    Dim positionStr As String
    Dim cnt As Variant
    
    On Error GoTo ErrorHandler
    '---Describe the process below---
    
    '◆◆◆ Where to insert characters: Change here for each purpose of use.
    insertPosition = ProcessingPosition.Back
    '◆◆◆◆◆
    
    'Express the insertPosition with characters
    Select Case insertPosition
    Case ProcessingPosition.Front
        positionStr = "Before the value"
    Case ProcessingPosition.Back
        positionStr = "Behind the value"
    Case Else
        positionStr = "Both before and after the value"
    End Select
    
    'Enter the insertion string
    insertedStr = InputBox("Please enter the character string to be inserted here." & _
                           vbNewLine & _
                           "The current insertion position is [" & _
                           positionStr & _
                           "】is.", "Specify the character string to insert", "")
        
    'Insert a string into the value of each cell
    For Each cnt In Selection
        Select Case insertPosition
        Case ProcessingPosition.Front
            cnt.Value = insertedStr & cnt.Value
        Case ProcessingPosition.Back
            cnt.Value = cnt.Value & insertedStr
        Case Else
            cnt.Value = insertedStr & cnt.Value & insertedStr
        End Select
    Next
    
        
ExitHandler:

    Exit Sub
    
ErrorHandler:

    MsgBox "An error has occurred, so exit" & _
           vbLf & _
           "Function name:" & FUNC_NAME & _
           vbLf & _
           "Error number" & Err.Number & Chr(13) & Err.Description, vbCritical
    
    GoTo ExitHandler
        
End Sub

Recommended Posts

[201911 ~ 201912] Recently created miscellaneous programs and tools, etc.
Summary of OSS tools and libraries created in 2016