1

ドキュメントをスキャンして、ドキュメントのセクションの開始位置と終了位置を特定しようとしています。ドキュメントにページ番号がリストされた目次がある場合があります。TOC はドキュメントの一部を識別しないため、取得したくありません。私はしばらくこれをいじっていて、何かに行き詰まっています。目次から行番号を付けて行をキャプチャすることは避けられないようです

ここに正規表現があります

verbose_item_pattern_3 = re.compile(r"""
  ^            # begin match at newline
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blank space
  I            # a capital I
  [tT][eE][mM] # one character from each of the three sets this allows for unknown case
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blankspace
  \d{1,2}      # 1-or-2 digits
  [.]?         # 0-or-1 literal .
  \(?          # 0-or-1 literal open paren
  [a-e]?       # 0-or-1 letter in the range a-e
  \)?          # 0-or-1 closing paren
  .*           # any number of unknown characters so we can have words and punctuation
  [^0-9]       # anything but [0-9]
  $           # 1 newline character
  """, re.VERBOSE|re.MULTILINE)

これは、キャプチャしたくない行の例です

test_string='\nItem 6.       TITLE ITEM 6..................................................25\n'

これが私がキャプチャしたいものの例です

test_string='\nItem 6.       TITLE ITEM 6 maybe other words here who knows  \n'

しかし、私が走るとき

re.findall(verbose_item_pattern_3,test_string)

結果は

['Item 6.       TITLE ITEM 6..................................................25\n']

私にとって興味深いのは、テスト文字列がこれである場合

test_string='PART I\nItem 1.       TITLE ITEM 1...................................................1\nItem 2.       TITLE ITEM 2..................................................21\n'

re.findall(verbose_item_pattern_3,test_string) でそれを実行します

結果は私が望むものに近いですが、それでも正しくありません

['Item 2.       TITLE ITEM 2..................................................21\n']

何もキャプチャされないはずです

4

2 に答える 2

2

あなたの正規表現は、3 つの理由で一致します。

  1. そのほとんどはオプションであるため、非常に具体的ではありません
  2. .*行全体を消費する があるため、最後の条件が[^0-9]適用されることはありません。その理由は次のとおりです。
  3. 改行文字自体が を満たす [^0-9]ため、[^0-9]行が数字で終わっていても は正常に一致します。

最小限の変更は、最後に否定的な後読みを使用することです。

verbose_item_pattern_3 = re.compile(r"""
  ^            # start-of-line
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blank space
  I            # a capital I
  [tT][eE][mM] # one character from each of the three sets this allows for unknown case
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blankspace
  \d{1,2}      # 1-or-2 digits
  [.]?         # 0-or-1 literal .
  \(?          # 0-or-1 literal open paren
  [a-e]?       # 0-or-1 letter in the range a-e
  \)?          # 0-or-1 closing paren
  .*           # any number of unknown characters so we can have words and punctuation
  $            # end-of-line
  (?<![0-9])   # NOT preceded by a decimal digit (via look-behind)
  """, re.VERBOSE|re.MULTILINE)

どちらも実際には改行文字と一致し^ないことに注意してください。改行文字の ( ) の直後または( ) の直前の位置$一致します。改行文字自体は一致の一部ではありません。^$

私は彼らのコメントをより正確なものに変更しましstart-of-lineend-of-line

また、 の後でも否定的な後読みを適用する方法にも注意してください$。このようにすると、バックトラッキングを防ぎ、正規表現を高速化するのに役立ちます。

于 2012-12-14T17:25:24.267 に答える
2

私の理解が正しければ、行の最後の文字が数字であり、正規表現が[^0-9]$.

これが正しく動作しない理由は、 が$の直前だけ\nでなく、文字列の最後にも一致するためです。ここで最終的に起こるのは、.*が数字に一致し、次に に[^0-9]一致し\n$文字列の末尾に一致することです。これがどのように機能するかを示すためにキャプチャ グループを使用する次の例を検討してください。

>>> re.match(r'(.*)([^0-9])$', '...12\n').groups()
('...12', '\n')

これを修正するには、次のよう[^0-9]に変更することで、改行文字の一致を防ぐことができ[^0-9\n]ます。

verbose_item_pattern_3 = re.compile(r"""
  ^            # begin match at newline
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blank space
  I            # a capital I
  [tT][eE][mM] # one character from each of the three sets this allows for unknown case
  \t*          # 0-or-more tabspace
  [ ]*         # 0-or-more blankspace
  \d{1,2}      # 1-or-2 digits
  [.]?         # 0-or-1 literal .
  \(?          # 0-or-1 literal open paren
  [a-e]?       # 0-or-1 letter in the range a-e
  \)?          # 0-or-1 closing paren
  .*           # any number of unknown characters so we can have words and punctuation
  [^0-9\n]     # anything but [0-9] and line breaks
  $           # 1 newline character
  """, re.VERBOSE|re.MULTILINE)

例 (上記の正規表現を使用):

>>> verbose_item_pattern_3.findall('\nItem 6.       TITLE ITEM 6.....25\n')
[]
>>> verbose_item_pattern_3.findall('\nItem 6.       TITLE ITEM 6.....\n')
['Item 6.       TITLE ITEM 6.....']
于 2012-12-14T17:25:34.860 に答える