I want to be able to enter only a string of the form "No. *" In the entry.
Rather than picking up the string of the entry and comparing it later, I want to prevent the input itself if the format is different.

For the time being, it is now working as expected, but is there any other good way?

If it's a smart method, I would like to adopt it.
Also, please point out any bad points in the following way.

import tkinter as tk
from tkinter import ttk
def func (p):
    # Limit the string to be inserted into the entry to "No. *" (* Is any character of 0 or more).
    Set len ​​(p)>= n and p [n-1] == "*" to avoid # IndexError.
    # Regarding the above, and does not see the latter when the former is False.
    # By the way, or does not see the latter if the former is True.
    jouken = \
        p == "" or \
        len (p) == 1 and p [0] == "N" or \
        len (p) == 2 and p [1] == "o" or \
        len (p) == 3 and p [2] == "." Or \
        len (p)>3 and True
    return jouken
if __name__ == "__main__":
    win = tk.Tk ()
    win.geometry ("300x300 + 0 + 0")
    sv = tk.StringVar ()
    vcmd = win.register (func)
    entry = ttk.Entry (win, textvariable = sv, validatecommand = (vcmd, "% P"), validate = "key")
    entry.grid ()
    win.mainloop ()
#Reference: https://python.keicode.com/advanced/tkinter-widget-entry-validate.php
  • Answer # 1

    I would like you to point out any points that are not good in the following way.

    It's not good, or there are points that can be improved.

    len () is called up to 4 times for each character input (improvement points)

    When you change the string to be inspected, you will change the code. (Maintainability problem)

    Input character starts with prefix → Check with startwith method of input character

    Check prefix.startswith while entering prefix ("N", "No")

    def func (p, prefix = "No."):
        return p.startswith (prefix) or prefix.startswith (p)
    if __name__ == "__main__":
        import unittest
        class TestInputValidataion (unittest.TestCase):
            def test_inputNo_ok (self):
                self.assertTrue (func (""))
                self.assertTrue (func ("N"))
                self.assertTrue (func ("No"))
                self.assertTrue (func ("No."))
                self.assertTrue (func ("No.100"))
            def test_inputNo_ng (self):
                self.assertFalse (func ("no."))
                self.assertFalse (func ("No,"))
                self.assertFalse (func ("No."))
        unittest.main ()

    Creating a unit test makes it easier to test when changing.

    If you continue to check the number input, there are other regular expressions, but
    Since the expression of the state being input tends to be a little complicated,
    It is good to use it together with the inspection method in prefix.startswith.

    check point: Prefix "No." expression
    If you want to change to something else, you only have to change it in one place.

  • Answer # 2

    In the current situation, after entering No., move the cursor to the 1st to 3rd characters.
    Because it is in a state where it can be freely changed to other characters
    If you want to strictly fix the leading "No.", you may need to review the conditions a little more.

      if len (p)<= 3:
            if p in ['N','No','No.']:
                return True
            else: else:
                return False
        else: else:
            if p [0: 3] =='No.':
                return True
            else: else:
                return False