LoginSignup
2
0

More than 5 years have passed since last update.

【Python】prompt-toolkitのtext_before_cursorとget_word_before_cursorの違い(おまけでWORD引数についての説明も)

Last updated at Posted at 2019-01-30

http-promptでそれぞれ使っていたため、自力で調べてみたけど違いがわからず、prompt-toolkitのIssuesで質問してみました

Question: What is the difference between text_before_cursor and get_word_before_cursor? · Issue #823 · prompt-toolkit/python-prompt-toolkit

動作環境

> python --version
Python 3.7.1

> pip3 list | grep prompt-toolkit
prompt-toolkit         2.0.8

それぞれの違い

text_before_cursor
その行のカーソル位置より前のテキストを返すプロパティ

get_word_before_cursor
(WORD=True (default))カーソル前の単語のまとまりを返す(Vimのi_CTRL-Wで消去する文字列のまとまりを返す)
(WORD=False)カーソル前からスペースまでの文字列を返す

text_before_cursor

その行のカーソル位置より前のテキスト

hogehoge hogege|Hello world!の場合、
hogehoge hogegeの部分が取得できる

get_word_before_cursor

カーソル前の単語を取得する

WORDの指定によって、取得する単語が変わる

  • WORD=True (default) カーソル前の単語のまとまりを返す(Vimのi_CTRL-Wで消去する文字列のまとまりを返す)
  • WORD=False カーソル前からスペースまでの文字列を返す

WORD=Falseの場合(default)

取得する文字列の正規表現は_FIND_WORD_REとなる

_FIND_WORD_RE = re.compile(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')

以下のどちらかの文字列

  • 単語を構成する文字の文字列([a-zA-Z0-9_]\wと同じ意味)
  • 記号の文字列([^a-zA-Z0-9_\s][^\w\s]と同じ意味)
>>> import re
>>> re.findall(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)', 'hoge hoge--hogege   guhehe')
['hoge', 'hoge', '--', 'hogege', 'guhehe']

Vimのi_CTRL-Wの単語のまとまりと同じ

WORD=Trueの場合

取得する文字列の正規表現は_FIND_BIG_WORD_REとなる

_FIND_BIG_WORD_RE = re.compile(r'([^\s]+)')

スペース以外の文字の文字列(スペース区切りとなる)

>>> import re
>>> re.findall(r'[^\s]+', 'hoge hoge--hogege   guhehe')
['hoge', 'hoge--hogege', 'guhehe']

スペースで区切られた文字列のリストが取得できた


get_word_before_cursorの処理が面白かったからメモ

  • 取得文字列の開始位置をカーソルからの相対位置で取得(find_start_of_previous_wordを呼び出す)
    • カーソル前のテキストを反転
    • WORDによって、取得文字列の正規表現を決める
    • マッチをテスト
    • マッチした文字列の開始位置(反転してるからend()で取得)
    • -演算子で負の数で返す(カーソルからの相対位置を返す)
  • カーソルの相対位置をもとに、文字列を取得する
>>> import re
# WORD=Falseとして動作確認してみる
>>> regex = re.compile(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_\s]+)')

# この文字列の末尾にカーソルがあると想定する
>>> text_before_cursor = 'Hello Python'

# 反転
>>> text_before_cursor_reverse = text_before_cursor[::-1]
>>> text_before_cursor_reverse
'nohtyP olleH'

# マッチのテスト
>>> iter = regex.finditer(text_before_cursor_reverse)

# 取得文字列の開始位置をカーソルからの相対位置で取得
>>> start = - next(iter).end(0)
>>> start
-6

# 文字列の取得
>>> text_before_cursor[len(text_before_cursor) + start:]
'Python'

単語とみなす文字列のまとまりを取得するための反転が面白い

ソースコード

    def get_word_before_cursor(self, WORD=False, pattern=None):
        """
        Give the word before the cursor.
        If we have whitespace before the cursor this returns an empty string.

        :param pattern: (None or compiled regex). When given, use this regex
            pattern.
        """
        text_before_cursor = self.text_before_cursor
        start = self.find_start_of_previous_word(WORD=WORD, pattern=pattern)

        if start is None:
            # Space before the cursor or no text before cursor.
            return ''

        return text_before_cursor[len(text_before_cursor) + start:]

    def find_start_of_previous_word(self, count=1, WORD=False, pattern=None):
        """
        Return an index relative to the cursor position pointing to the start
        of the previous word. Return `None` if nothing was found.

        :param pattern: (None or compiled regex). When given, use this regex
            pattern.
        """
        assert not (WORD and pattern)

        # Reverse the text before the cursor, in order to do an efficient
        # backwards search.
        text_before_cursor = self.text_before_cursor[::-1]

        if pattern:
            regex = pattern
        elif WORD:
            regex = _FIND_BIG_WORD_RE
        else:
            regex = _FIND_WORD_RE

        iterator = regex.finditer(text_before_cursor)

        try:
            for i, match in enumerate(iterator):
                if i + 1 == count:
                    return - match.end(0)
        except StopIteration:
            pass

参考文献

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0