質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.33%

  • Python

    9218questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7412questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Anaconda

    180questions

re.searchでのエラー

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 499

hershel

score 4

会話AIを作ろうと思い
http://sandmark.hateblo.jp/entry/2017/10/10/014717
https://github.com/sandmark/unmo/tree/79b4b990da6220543208879551737ac31e6cddf0
のプログラムを参考にして「吾輩は猫である」の文章を一文ずつ(句点。で文章を区切りました。)会話させたところ、途中でエラーが発生しました。
こちらが発した文章の中から知っている単語を探すときにエラーを出します。
該当箇所のコードは

def response(self, text):
        """ユーザーの入力に合致するパターンがあれば、関連するフレーズを返す。"""
        for ptn in self._dictionary.pattern:
            matcher = re.search(ptn['pattern'], text)
            if matcher:
                chosen_response = choice(ptn['phrases'])
                return chosen_response.replace('%match%', matcher[0])
        return choice(self._dictionary.random)


matche = の行で以下のエラー文が出ます

Traceback (most recent call last):

  File "<ipython-input-53-c0f899393dfc>", line 1, in <module>
    runfile('C:/***/repos/train.py', wdir='C:/Users/takeshi/Desktop/AI/repos')

  File "C:\***\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 705, in runfile
    execfile(filename, namespace)

  File "C:\***\Anaconda3\lib\site-packages\spyder\utils\site\sitecustomize.py", line 102, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "C:/***/repos/train.py", line 31, in <module>
    response = proto.dialogue(Line)

  File "C:\***\repos\unmo.py", line 44, in dialogue
    response = self._responder.response(text)

  File "C:\***\repos\responder.py", line 58, in response
    matcher = re.search(ptn['pattern'], text)

  File "C:\***\Anaconda3\lib\re.py", line 182, in search
    return _compile(pattern, flags).search(string)

  File "C:\***\Anaconda3\lib\re.py", line 301, in _compile
    p = sre_compile.compile(pattern, flags)

  File "C:\***\Anaconda3\lib\sre_compile.py", line 562, in compile
    p = sre_parse.parse(p, flags)

  File "C:\***\Anaconda3\lib\sre_parse.py", line 855, in parse
    p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, 0)

  File "C:\***\Anaconda3\lib\sre_parse.py", line 416, in _parse_sub
    not nested and not items))

  File "C:\***\Anaconda3\lib\sre_parse.py", line 768, in _parse
    source.tell() - start)

error: missing ), unterminated subpattern

エラーは「妹も負けずに一杯を附加した」
を読み込ませたときに起こります。
「吾輩は猫である」を全く読み込ませない状態ではこの文章を読み込ませても問題なく動作し、「吾輩は猫である」を最初から順番に読み込ませたときのみエラーが出ます。
しかしこれ以前の文章には「妹」も「附加」も出てこないためなぜここでエラーが出るのか不明です。
ご教授いただけると幸いです。

追記
ptn['pattern']にはそれまで会話の中に登場した名詞が入ります。
会話を行うとその中に登場した名詞や文章を学習してファイルに

私 私はリンゴが好きです|私はプログラムです
リンゴ 私はリンゴが好きです
プログラム 私はプログラムです

といった形で情報を入れます。
先頭の単語がptn['pattern']にあたります。

関連するコードは

import re
from janome.tokenizer import Tokenizer


class Dictionary:
    """思考エンジンの辞書クラス。

    クラス変数:
    DICT_PATTERN -- パターン辞書のファイル名
    TOKENIZER -- 形態素解析器

    スタティックメソッド:
    make_pattern(str) -- パターン辞書読み込み用のヘルパー
    pattern_to_line(pattern) -- パターンハッシュをパターン辞書形式に変換する
    analyze(str) -- 文字列strを形態素解析する

    プロパティ:
    pattern -- パターン辞書
    """

    DICT_PATTERN = '***.txt'
    TOKENIZER = Tokenizer()

    def __init__(self):
        """ファイルから辞書の読み込みを行う。"""
        with open(Dictionary.DICT_RANDOM, encoding='utf-8') as f:
            self._random = [l for l in f.read().splitlines() if l]

        with open(Dictionary.DICT_PATTERN, encoding='utf-8') as f:
            self._pattern = [Dictionary.make_pattern(l) for l in f.read().splitlines() if l]

    def study(self, text):
        """パターン辞書をメモリに保存する。"""
        self.study_pattern(text, Dictionary.analyze(text))

    def study_pattern(self, text, parts):
        """ユーザーの発言textを、形態素partsに基づいてパターン辞書に保存する。"""
        for word, part in parts:
            if self.is_keyword(part):  # 品詞が名詞であれば学習
                # 単語の重複チェック
                # 同じ単語で登録されていれば、パターンを追加する
                # 無ければ新しいパターンを作成する
                duplicated = next((p for p in self._pattern if p['pattern'] == word), None)
                if duplicated:
                    if not text in duplicated['phrases']:
                        duplicated['phrases'].append(text)
                else:
                    self._pattern.append({'pattern': word, 'phrases': [text]})

    def save(self):
        """メモリ上の辞書をファイルに保存する。"""
        with open(Dictionary.DICT_RANDOM, mode='w', encoding='utf-8') as f:
            f.write('\n'.join(self.random))

        with open(Dictionary.DICT_PATTERN, mode='w', encoding='utf-8') as f:
            f.write('\n'.join([Dictionary.pattern_to_line(p) for p in self._pattern]))

    @staticmethod
    def analyze(text):
        """文字列textを形態素解析し、[(surface, parts)]の形にして返す。"""
        return [(t.surface, t.part_of_speech) for t in Dictionary.TOKENIZER.tokenize(text)]

    @staticmethod
    def pattern_to_line(pattern):
        """パターンのハッシュを文字列に変換する。"""
        return '{}\t{}'.format(pattern['pattern'], '|'.join(pattern['phrases']))

    @staticmethod
    def is_keyword(part):
        """品詞partが学習すべきキーワードであるかどうかを真偽値で返す。"""
        return bool(re.match(r'名詞,(一般|代名詞|固有名詞|サ変接続|形容動詞語幹)', part))

    @staticmethod
    def make_pattern(line):
        """文字列lineを\tで分割し、{'pattern': [0], 'phrases': [1]}の形式で返す。
        [1]はさらに`|`で分割し、文字列のリストとする。"""
        pattern, phrases = line.split('\t')
        if pattern and phrases:
            return {'pattern': pattern, 'phrases': phrases.split('|')}

    @property
    def pattern(self):
        """パターン辞書"""
        return self._pattern
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • LouiS0616

    2018/07/22 10:25

    ptn['pattern'] にはどんな値が入るのですか。

    キャンセル

  • LouiS0616

    2018/07/22 14:56

    追記ありがとうございます。では、実際にエラーが起きるとき、ptn['pattern'] にはどのような値が入っているのでしょうか。出力して確かめてみてください。

    キャンセル

  • hershel

    2018/07/22 15:11

    '※(「'となっていました。青空文庫の注釈文の部分ですね。これは(が悪さをしているという事でしょうか?もしそうならかなり初歩的なミスですみません。

    キャンセル

回答 1

checkベストアンサー

0

これは(が悪さをしているという事でしょうか?

はい。(は正規表現のメタ文字で、必ず括弧閉じとセットで使います。

>>> import re
>>> re.compile('(')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...中略...
sre_constants.error: missing ), unterminated subpattern at position 0
>>>
>>> re.compile('()')  # セットならOK
re.compile('()')
>>> re.compile('\(')  # エスケープしてもOK
re.compile('\\(')

メタ文字を含み得る文字列を正規表現に突っ込むときは、エスケープした方が良いでしょう。

>>> chs = '('
>>> re.compile(chs)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...中略...
sre_constants.error: missing ), unterminated subpattern at position 0
>>>
>>> re.escape(chs)
'\\('
>>> re.compile(re.escape(chs))
re.compile('\\(')

Python 標準ライブラリ » re — 正規表現操作 » re.escape

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/22 21:02

    ありがとうございます。正規表現についてもう少し勉強します。

    キャンセル

同じタグがついた質問を見る

  • Python

    9218questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7412questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Anaconda

    180questions