PerlまたはPythonでのlexのような機能のエミュレーション
質問
こちらが取引です。複数の正規表現に基づいて文字列を1行でトークン化する方法はありますか?
1つの例:
すべてのhrefタグ、対応するテキスト、および異なる正規表現に基づいた他のテキストを取得する必要があります。 したがって、3つの式があり、行をトークン化して、すべての式に一致するテキストのトークンを抽出したいと思います。
これは実際にflex(Adobeと混同しないでください)を使用して行いました。これは古き良きlexの実装です。 lexが提供する 「アクション」を実行してこれを行うエレガントな方法式に基づいています。方法を制御できます lexもファイルを読み取ります(ブロック/行ベースの読み取り)。
問題は、flexが実際にトークン化ジョブを実行するC / C ++コードを実際に生成することです。私が持っています これらすべてをラップするmakeファイル。 perl / pythonが何らかの方法で同じことをできるかどうか疑問に思っていました。そのすべてをやりたい 単一のプログラミング言語自体が好きです。
トークン化は、アプリケーションの一部としてやりたいことの1つにすぎません。
perlまたはpythonとは別に、どの言語(機能的)でもこれを実行できますか?
ここでPLYとANTLRについて読みました(解析、どこで私はそれについて学びます)。
しかし、Python自体で自然にそれを行う方法はありますか?私の無知を許しますが、これらのツールは人気のある製品/サービスで使用されていますか?
ありがとう。
解決
Webページからリンクを解析した後に具体的にしている場合、Perlの WWW: :Mechanize モジュールは、非常にエレガントな方法で物事を把握します。 Stack Overflowの最初のページを取得し、すべてのリンクを解析して、テキストと対応するURLを出力するサンプルプログラムを次に示します。
#!/usr/bin/perl
use strict;
use warnings;
use WWW::Mechanize;
my $mech = WWW::Mechanize->new;
$mech->get("http://stackoverflow.com/");
$mech->success or die "Oh no! Couldn't fetch stackoverflow.com";
foreach my $link ($mech->links) {
print "* [",$link->text, "] points to ", $link->url, "\n";
}
メインループでは、各 $ link
は WWW :: Mechanize :: Link オブジェクト。したがって、テキストとURLを取得するだけでなく、
すべて、最高
ポール
他のヒント
and
これらのモジュールを使用して、非常に大きく複雑なWebページを処理しました。
あなたが本当にHTMLを解析したいだけのように聞こえますが、そうするための素晴らしいパッケージを見ることをお勧めします:
または!次のいずれかのパーサーを使用できます。
この例は、BeautifulSoup ドキュメントからのものです:
from BeautifulSoup import BeautifulSoup, SoupStrainer
import re
links = SoupStrainer('a')
[tag for tag in BeautifulSoup(doc, parseOnlyThese=links)]
# [<a href="http://www.bob.com/">success</a>,
# <a href="http://www.bob.com/plasma">experiments</a>,
# <a href="http://www.boogabooga.net/">BoogaBooga</a>]
linksToBob = SoupStrainer('a', href=re.compile('bob.com/'))
[tag for tag in BeautifulSoup(doc, parseOnlyThese=linksToBob)]
# [<a href="http://www.bob.com/">success</a>,
# <a href="http://www.bob.com/plasma">experiments</a>]
PyParsing をご覧になりましたか
ホームページから:
これは、「Hello、World!」を解析するプログラムです。 (または&quot;、!&quot;という形式の挨拶):
from pyparsing import Word, alphas
greet = Word( alphas ) + "," + Word( alphas ) + "!" # <-- grammar defined here
hello = "Hello, World!"
print hello, "->", greet.parseString( hello )
プログラムは次を出力します。
Hello, World! -> ['Hello', ',', 'World', '!']
Webスクレイピングに問題がある場合は、 Webを参照することをお勧めします:: Scraper は、XPathまたはCSSセレクターを介して簡単に要素を選択できます。 (ドイツ語) Web :: Scraperでトーク、ただし、それをbabelfishで実行するか、コードサンプルを見るだけで、構文の概要をすばやく確認できます。
HTMLを手動で解析するのは面倒で、既成のHTMLパーサーの1つを使用することであまり得られません。 HTMLのバリエーションが非常に限られている場合は、巧妙な正規表現を使用して取得できますが、既にハードコアパーサーツールを使用している場合は、HTMLが解析対象の健全性よりもはるかに規則的であるように聞こえます正規表現。
perlop から:
lexライクスキャナーの便利なイディオム
/ \ G ... / gc
です。組み合わせることができます このようないくつかの正規表現は 文字列を部分ごとに、異なることを行う どの正規表現に応じたアクション 一致しました。各正規表現は一致しようとします 前のものは続きます。LOOP: { print(" digits"), redo LOOP if /\G\d+\b[,.;]?\s*/gc; print(" lowercase"), redo LOOP if /\G[a-z]+\b[,.;]?\s*/gc; print(" UPPERCASE"), redo LOOP if /\G[A-Z]+\b[,.;]?\s*/gc; print(" Capitalized"), redo LOOP if /\G[A-Z][a-z]+\b[,.;]?\s*/gc; print(" MiXeD"), redo LOOP if /\G[A-Za-z]+\b[,.;]?\s*/gc; print(" alphanumeric"), redo LOOP if /\G[A-Za-z0-9]+\b[,.;]?\s*/gc; print(" line-noise"), redo LOOP if /\G[^A-Za-z0-9]+/gc; print ". That's all!\n"; }
また、 pQuery をチェックしてください。もの....
use pQuery;
pQuery( 'http://www.perl.com' )->find( 'a' )->each(
sub {
my $pQ = pQuery( また、 pQuery をチェックしてください。もの....
use strict;
use warnings;
use Parse::RecDescent;
my $grammar = q{
alpha : /\w+/
sep : /,|\s/
end : '!'
greet : alpha sep alpha end { shift @item; return \@item }
};
my $parse = Parse::RecDescent->new( $grammar );
my $hello = "Hello, World!";
print "$hello -> @{ $parse->greet( $hello ) }";
# => Hello, World! -> Hello , World !
ただし、要件がHTML / Webを超えている場合は、以前の「Hello World!」 Parse :: RecDescent ...
<*>
恐らくこのハンマーを割るには多すぎる大きなハンマー;-)
);
say $pQ->text, ' -> ', $pQ->toHtml;
}
);
# prints all HTML anchors on www.perl.com
# => link text -> anchor HTML
ただし、要件がHTML / Webを超えている場合は、以前の「Hello World!」
恐らくこのハンマーを割るには多すぎる大きなハンマー;-)
ブルーノの例を修正してエラーチェックを含める:
my $input = "...";
while (1) {
if ($input =~ /\G(\w+)/gc) { print "word: '$1'\n"; next }
if ($input =~ /\G(\s+)/gc) { print "whitespace: '$1'\n"; next }
if ($input !~ /\G\z/gc) { print "tokenizing error at character " . pos($input) . "\n" }
print "done!\n"; last;
}
(スカラー// gの使用は、残念ながら、$ 1などの変数の使用を本当に避けられない1つの場所であることに注意してください。)