Regular Expression(正規表現) Part14 [無断転載禁止]©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
Regular Expressionスレです。 質問する場合は必ず実装言語や処理系ソフトウェア名を示してください。 前スレ Regular Expression(正規表現) Part13 http://echo.2ch.net/test/read.cgi/tech/1415149975/ 次スレは>>980 宜しく 天ぷら等2以降 Ruby でも、 'こんにちは。'.gsub(/(.)+/, $1) #=> "。" >>457 .NETはCaptureCollectionってのに入れてくれるみたいよ ただフルマッチとキャプチャリンググループと両方1度に必要なければ /(.){1}/みたいに正規表現変えれば配列に入れられるよね >>455 すみません。 教えて頂いたサイトを見ても分かりません。 簡単に解説をお願いしたいのですが。 単純に最後にマッチした部分ってことじゃないかな。赤ラクダにそう書いてある。 C# は知らない。誰か翻訳してあげて。 >>460 キャプチャグループに量指定子がついてるとそのキャプチャグループの箇所に複数回マッチする可能性があるよね。 んで複数回マッチした場合は最後にマッチしたやつがそのキャプチャグループに入ってるってこと "こんにちは。”に対して、/(.)+/でマッチをかけると 最初にピリオドが“こ”にマッチしてそれをグループ1に入れて 次に+を見てまたマッチするか繰り返す 今度はピリオドに”ん”がマッチするからそれをグループ1に入れて、、、 あとは繰り返し “こんにちは。”が/(.)+/にフルマッチした時点でグループ1に入ってるのは”。” /(.+)/ =~ 'こんにちは。' $1 は、'こんにちは。' /(.)+/ =~ 'こんにちは。' $1 は、'。' 上は、1回しかマッチしていない、最長マッチ。 下は、1文字のマッチで、6回マッチして、最後のマッチが、'。' >>463 うーん、1文字マッチで6回マッチするのはどっちも同じじゃない? キャプチャグループに入れる回数の違い 詳細 ○○表現 尼での評価がよかったので買ってみたが全然 リファレンスにもならない やっぱり海外の訳本はだめだ、すくなくとも自分には良書でなかった フクロウ本のことかな 中の仕組みを理解するための本であって リファレンス本でも入門書でもないからね >>464 そういうマッチャー自分で作る時はスキップするよう作るけど 正規表現エンジンはしないのか 複雑だとやってられないとかか 試しに for pat in '([cd])+' '(.)+' '.*(.)' ; do perl -Mre=debug -e '$pat = shift; print "abcd" =~ /$pat/ ,"\n" ;' "$pat" ; done ってやってみた。最適化してそうだ。.*(.) は意味的には同じだと思うがバックトラックの分だけ不利。 Perl のソースコードを確認したわけではないので断定はしかねるが。 今はサンプルだからいいけど 長大な文章じゃスキップで最適化しないとやってられないよな 個人的には (.)+ と書くべき理由が思い当たらない。 正規表現とギターの速弾きが出来る奴は賢いと尊敬している 複数のSQL文の書かれているSQLファイルから、DBの処理単位でSQL文を逐次取り出す正規表現が書きたいのですがどうしたら良いですか? 厳密なものでは無くても良くて英文字から始まってセミコロンで終わるというもので良いのです。 ただ、SQL分は行頭から始まるとは限らず、セミコロンの直後に次のSQL文が始まったり、空白文字などがあってからSQLの文が始まったりすることもあります。 また、文中に出てくるエスケープされたセミコロンや文字列中のセミコロンは文末の対象になって区切られては困るのでそれはスキップして評価がしたいです。 文字列の内外を判断するの難しい・・・・難しくない? multilineのオプション付けて ;でsplitしただけじゃだめなん >>474 それが含まれる時点で無理に正規表現一行で書くのはいつもあきらめる ちゃんとやるなら文字列中のエスケープされたシングルクォートとかも処理しないとダメだし正規表現でやるのはすごく大変だと思う 正規文法ではかなり厳しい印象で, BNFの管轄だと思うおよね 1. ; で分割して、配列に入れる 2. 配列の各要素から、余分なものを削除する 2 のルールを、厳格に決めればよい Ruby で作る方が速い 正規表現は置いといて DB用意して""で囲まれた部分をテキストとしてDBに入れながらID取得 本文側はIDに置き換える あとは正規表現を使っても使わなくてもいいが;で分割 最後にまたID部分に元のテキストを流し込む そこであきらめんなよ! 正規表現だけで乗り切ろうという気概を見せろよ! (シングル|ダブル)クオート文字列って正規言語で表せる範囲にあるんかね? 文脈自由言語では表せるけど どの正規表現がつかえるのかがわからん 環境を明示してくれないとなー /\"([^\"]*)\"/ =~ 'a"bc"d' $1 #=> bc "〜" で、〜には、" 以外の文字列が入る "のエスケープや'もあるし 'a"b\"c'd"e' 沢山ご回答ありがとうございます。 皆さんのご意見を伺った限り、やはり正規表現一本では難しそうですよね… はじめは前処理で既成のsqlパーサなどを通して、きれいに整形して別ファイルに保存してから処理する方法も検討していましたが、 できれば現物ファイルを生のまま読み込んで正規表現でなんとか行けないかなと思い試行錯誤していて、 うまい書き方が全然できなくてここに書き込みさせて頂いた次第です。 >>483 使用できる正規表現はPCREです。 具体的にはPHPで省メモリで巨大なSQLファイルを実行する仕組みが作りたくて 相談させてもらいました。自分の頭の中のアイデアでは 1.fileをbufsize分readして 2.正規表現でマッチするかチェック 3.マッチしていたらそのSQLを実行。マッチした文より、先の部分は次の実行のためにバッファに積んで1へもどる 4.マッチしていない場合は更にbufsize分read、2->4を繰り返す。 こんなイメージでした。 それを鑑みると、>>480 さんのアイデアはちょっとありかなとも思います。 スレ違いなっちゃいますが、regexを使わずプログラム上でクオートの始まりと終わりを正しく 処理できれば随分楽できそうな気がします。一考の余地ありですかね? "'", "\"" '"', '\'' クォーテーション内にクォーテーションがある、入れ子状態が難しい。 クォーテーションを、\ でエスケープしたりもあるし XML Parser とか、プログラム実行の命令木とか、解析ツールを使わないと無理。 プログラミングで何とかできる、範囲を超えている そもそも、入れ子状態にどういうパターンがあるのか、 全列挙して考えるのが、非常に難しい 入れ子の入れ子とか、再帰的に入れ子するかも知れないし >>486 こういう感じでどうだろう [a-zA-Z](?:\\"|\\'|[^"';]|(["'])(?:\\\1|(?:(?!\1).))*(?<!\\)\1)*; 英数字で始まって、\"や\'は許す;で終わる文字列 頭に^\s*を付けたほうがいいかもしれないけど 文字列は、" ' "、' " '、" \" "、' \' 'は許す( ; もOK) ところで、" ' " ' "とは書けるんだっけ? こういう括弧のネストが可能なら、正規表現の方もネスト構文や条件構文を使わないといけないけど (俺は使ったことはないけど) 仕様を確定させるのが難しい。 単なるテキストには、ルールが無いだろ XML とか、プログラム言語には、仕様があって、 ルール違反の書き方を許さないから、プログラムで判定できる だから、まずこう書いたらエラーにする、という仕様を決めるべき >>491 https://ronsavage.github.io/SQL/sql-2003-2.bnf.html こいつのcharacter string literalとか読め ちゃんと規格化されてるんだからさ その上で正規表現で書くのは難しいって話 試しに Perl でやってみた。最も楽観的な想定ならこのくらいまでは手抜きできる。 use strict; my $comment = qr/(?:--.*?\n)/ ; my $literal_ch = qr/(?:\'\'|[^\'])/ ; my $ch_str_literal = qr/(?:\'(?>$literal_ch*)\')/ ; my $other_ch = qr/[^\';]/ ; my $some_str = qr/(?:$comment|$ch_str_literal|$other_ch)/ ; my $statement = qr/(?:$some_str*;)/ ; my $text = ''; while (<>){ $text .= $_; while ( $text =~ s/^$statement// ){ print("Found:$&\n") }} 文字列リテラルの中の文字の記法に特に対処すべき拡張があるなら $literal_ch に加えれば良い。 " は識別子を書くためのものだが '、;、-- のどれかが入る可能性があるなら $other_ch と $some_str に加えればいいだろう。 多分、問題はそこではない。この例では行単位の入力だから面倒な問題を回避できているが、そうでない場合の問題だ。 たとえばコメントの始まりの - までしか読まれていないという場合。もっと読まなければコメントかどうか判断できない。 あるいは文字列リテラルの中で ' が現れた場合。それは文字列リテラルの終わりなのか、それともリテラルの ' を表す '' の 1 文字目なのか。 こういう処理を自分で書くのは難しくはなくても面倒だし、処理速度も遅い。だから結局 flex を使ったりする。 仕様通りのParser とか、構文解析ツールが必要 それらを使って出力された、抽象構文木を使うのがよい ★タイトル ★★タイトル 上のものにマッチさせたいのですが、 ^★.*$ としてしまうと、下まで含まれるのですが、どうしたらいいでしょうか ↑解答どうも できなかったです ちなみにmeryというテキストエディタの正規表現です 何の言語かはわかりませんが https://regex101.com/r/YyXfr8/1 鬼雲みたいだし動くと思うんだけど, 先頭とか末尾に余計なスペース入ってない? ↑ありがとうございます。行けました。 .*の前に否定を入れればいいんですね 正規表現をちゃんと論理的に導きたいと思って参考になる本を 買ったら必要な予備知識に群とか環が出てきて即諦めた 正規表現周りの開発をしてる人達はすごい人達なんだなぁ すごさを直で実感出来た 用語に慣れてないだけだろ やってることは大したことじゃない まぁ膨大な時間と労力をかければ自分にも分かるんだろうけど 現実的じゃないんだよなぁ(人の何倍も時間かかるだろうし) これからは正規表現技術者の努力に感謝しながら正規表現を 使おうと思います(^^)> JavaScriptによる正規表現チェッカー くっそ長いので短縮 https://goo. gl/CE3aZ8 https://fatiherikli.github.io/fil/#eyJwYXRoIjoiSmF2YVNjcmlwdFRlc3QxLmpzIiwic291cmNlIjoiLyog5q2j6KaP6KG o54++44Oe44OD44OB44OG44K544OIICovXG5cbi8vIOato+imj+ihqOePvlxudmFyIHJlID0gbmV3IFJlZ0V4cCgv XFxkKy9nKTtcblxuLy8g44OG44Kt44K544OIXG52YXIgdGV4dCA9IChmdW5jdGlvbiAoKSB7LypcbmFhYVxuYmIx MmJcbmM1NjdjYzg5XG4qL30pLnRvU3RyaW5nKCkuc3BsaXQoL1xcbi8pLnNsaWNlKDEsLTEpO1xuXG5jb25zb2x lLmxvZyhcIlJlZ0V4cDpcIiwgcmUudG9TdHJpbmcoKSlcbmNvbnNvbGUubG9nKFwiVGV4dDpcIiwgdGV4dCk7XG5c bnRleHQuZm9yRWFjaChmdW5jdGlvbihsaW5lKSB7XG4gICAgY29uc29sZS5sb2coXCJsaW5lOlwiLCBsaW5lKTtcbiA gICB2YXIgcmVzdWx0ID0gbGluZS5tYXRjaChyZSk7XG4gICAgaWYocmVzdWx0KVxuICAgICAgICBjb25zb2xlLmxv ZyhcInJlc3VsdDpcIiwgcmVzdWx0KTtcbiAgICBlbHNlXG4gICAgICAgIGNvbnNvbGUubG9nKFwicmVzdWx0OlwiLCBcIm51bGxcIik7XG59KVxuIn0 ちょっと修正 https://goo. gl/M2Fn68 Linuxに触れるまで正規表現に方言があるなんて知らなかった 基本正規表現だの拡張正規表現だの vimの置換で悩んでたら原因がエスケープの有無が原因とかもうね ある程度は使えるが先読みとか後読みとか僅かでも深入りすると余計に混乱する 小さい世界で囲い込まれてれば楽だよな ただし何かの拍子ではみ出した時に世界の広さを知って己の無力さを痛感する よくあるパターン 僕の知り合いの知り合いができたパソコン一台でお金持ちになれるやり方 役に立つかもしれません グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』 QBPEH HTMLの解析を正規表現でやりたいのですが <a href="xxxxx"><img src="yyyyy" /></a> という風に、<a> で括られた img の src だけを抽出したいんですけど どうしたらいいのでしょう。 <a> で括られてない <img src="yyyyy" /> は除外したいのです。 あ、すみません <a href="xxxxx"><img src="yyyyy" /></a> <a href="xxxxx">あああ<img src="yyyyy" /></a> <a href="xxxxx"><img src="yyyyy" />いいい</a> <a href="xxxxx">あああ<img src="yyyyy" />いいい</a> <a href="xxxxx"><img src="yyyyy" /><div>あああ<div></a> みたいに、<a> の中は <img> 以外のゴミも入ってきます。 ※ゴミは無視したい >>512 ^<a\b.+<img src="([^"]+)".+</a>$ ↓ $1 >>513 <a href=""></a><img src="1.jpg"><a href=""></a> 頑張ってみてもこの程度が限界 https://regex101.com/r/VYrYNO/1 で, >>511 がHTMLの解析を正規表現だけでやる理由は何だ? Pythonのhtml.parser, RubyのNokogiri, PHPならGoutter, それ以外の言語でも間違いなくHTMLパーサは誰かしら作ってる そんな中で何故正規表現だけで?ぶっちゃけこういう用途には向いてない, というかHTMLの構文規則は正規言語を超えるんだけど, 分かってる? パーサかましてXPathで必要な情報だけ抜くのが基本だしな どうしても使えないっていう理由があるなら仕方ないけど 鬼雲限定 <a (?~</a>)<img src="([^"]+)"[^>]*>(?~<a )</a> ■変更前 004a34 A521n2 785b66 ■変更後 0049934 99521992 7859966 ---------------------- 数値以外を99に置換したいです お願いします 木構造のものは、正規表現じゃ無理 1< 2< abc 3> 4> 2<からの最短マッチで、対応する3>を取れるけど、 1<からの最短マッチで、対応する4>を取れない。 3>にマッチしてしまうから 1< 2< 3< abc 4> 5> 6> これでも、2<と5>をマッチさせられない。 最長・最短マッチでも、マッチしない CSS セレクターを使う、jQuery, RubyのNokogiri などを使え。 これらの使い方は、ほぼ同じ >>518 数値以外と簡単に言うが改行文字や空白等の扱いはどうするんだ 変換対象文字をちゃんと明示しないと /[^0-9]/99/g こんなもんが欲しいわけではあるまい とりあえずASCII印字可能文字に限るなら /[\x21-\x2F\x40-\x7E]/99/g だが当然マルチバイト文字は対象外 >>519 再帰を使えば、対応する括弧のネスト対応ぐらいならできるらしいよ(鬼雲、PCRE) <([^<>]++|(?R))*> # [^<>]++は(?>[^<>]+)としてもよい(どっちもバックトラックしないと思う) # (?R)は、(?0)とも書ける # (<([^<>]++|(?1))*>) \g<-n>を使ってもできる(鬼雲だけ?) (<(?:\g<-1>|[^<>])*>) # \g<-1>は(?-1)とも書ける # ここでは\g<-1>を先に書いたが上と同じく後ろに書いても同じ https://regex101.com/r/VYrYNO/1 なぁこれメンテしたいか?というか出来るか?なぁ? (?i:<a(?:\s+[a-z][a-z0-9]*(?:=(?:"[^"]*"|'[^']+'))?)*>) ((?: (?i:<img(?:\s+(?:src="([^"]+)"|[a-z][a-z0-9]*(?:=(?:"[^"]*"|'[^']+'))?))*(?:\s*\/)?>) |(?i:<([a-z][a-z0-9]*)(?:\s+[a-z][a-z0-9]*(?:=(?:"[^"]*"|'[^']+'))?)*>(?1)<\/\3>) |(?i:<[a-z][a-z0-9]*(?:\s+[a-z][a-z0-9]*(?:=(?:"[^"]*"|'[^']+'))?)*\s*\/>|.*?))*) (?i:<\/a>) 文字列の中から数字13桁(それ未満でも超えてもNG)を抽出するにはどうしたらいいでしょう JANコードらしきを抜き取りたいのです。 候補を抽出してから後でチェックデジット計算しますので 数字13桁のみで大丈夫です。 \b[0-9]{13}\b とか (?<![0-9])[0-9]{13}(?![0-9]) とか 携帯だから試してない 先頭と末尾も考慮すると https://regex101.com/r/xT760t/2 (?:(?<=[^0-9])|^)[0-9]{13}(?:(?=[^0-9])|$) ただかなりバックトラックするから性能は悪い どうせチェックディジット確認するなら13桁以上で全抽出して桁数チェック追加した方がマシに見える https://regex101.com/r/xT760t/4 [0-9]{13,} 結構、難しい A <13桁の数字> B A の部分が、文字列の先頭か、数字以外で、 B の部分が、文字列の末尾か、数字以外 文字列操作可能なら両端に数字以外の文字を付加して [^0-9][0-9]{13}[^0-9] かな >>531 先読み後読みは先頭や末尾にも一致するからそういうのは無駄 >>530 の二つ目で完成している >>534 せやな, 否定前後読みならそのままでよかったわ(肯定で試しちゃった) ただどのみちバックトラック多くて無駄だから正規表現だけでやるのでなければ13桁以上でマッチングして桁数判定入れるべきだと思う 13桁を超えていても候補として受け取っておいて チェックデジットの計算の手前で落とします。 どうもありがとうございました。 文字列の先頭の文字以外を*に変換する というのはどう書けばいいでしょうか? こういうこと? $perl -pe 's/(?!^)./*/g' alpha a**** beta b*** gamma g**** $ 良い方法かどうかはわからないが。 perl -pe 's/(?<!^)./*/g' とすべきだったかな。 1 2 3 の3つの文字を、順番不同で、必ず各々、1つ以上含む a23b1 → 真 1a2 → 偽 これは順番の組み合わせだから、正規表現で出来ますか? >>542 先読みが使えれば ^(?=.*1)(?=.*2)(?=.*3) サクラエディタで <>で囲まれていないaaaをあああにしたいです <aaab>aaa<caaadaaa>baaadeaaa<ccc>baaad<baaa>aaabaaadaaa<ee> ↓ <aaab>あああ<caaadaaa>bあああdeあああ<ccc>bあああd<baaa>あああbあああdあああ<ee> >([^<>a]*?)(aaa)([^<>a]*?)< >$1あああ$2< だと「>aaa<」や「>baaad<」は置換できるけど「>baaadeaaa<」や「>aaabaaadaaa<」が置換できずに残る そこで >([^<>a]*?)(aaa)([^<>a]*?)(aaa)([^<>a]*?)< >$1あああ$2あああ$3< と変換するわけですが当然「>aaabaaadaaa<」が残り… <>に囲まれていないaaaが沢山あるので変換しきれません 何とかならないでしょうか []内のa取っ払って ぜんぶ変換できるまで何回もやったら? (>[^<]*?)aaa([^>]*?<) aaa(?=[^>]*<) 前後に必ずタグがあるならこれなら一回 >>545 >>546 できた!できました! ありがとうございます ● パターン1, (\d+)月(\d+)日 パターン2, (\d+)月(\d+)数字以外(\d+)日 これを一回で取得したい ●対象データ 7月1日 7月2〜4日 7月6から10日 7月12・13日 ●希望する結果 7,1 7,2,4 7,6,10 7,12,13 お願いします 取得って何だよ変数に入ればいいのか置換結果として取得したいのか >>548 ほんまにそれが希望する結果? 数字とりだしてるだけなんだけど。 数字取り出して変数に入れるだけなら /(\d+)月(\d+)(?:\D+(\d+))?日/gu で仕舞いだが 変数にキャプチャしたいのか置換で取り出したいのかくらい書こうな C#で正規表現を使ってHTML内から文字コードをとってきたいのですが 以下の場合だと"UTF"としか取得できません。 "UTF-8"と取得する場合どうすればいいでしょうか? <[^>]*\bcharset\s*=\s*[""']?(?<charset>\w+)\b <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> >>556 HTMLは扱いが難しいからパーサ使った方がいい どうしても正規表現だというなら, 1. とりあえず的な修正 https://regex101.com/r/sIUmzD/2 /<[^>]*\bcharset\s*=\s*(?:([^\s"'=><`]+)|'([^']*)'|"([^"]*)")\b/$1$2$3/i 2. もう少し気合の入れた修正 https://regex101.com/r/sIUmzD/1 |<meta (?:\s+[^\s"'>/=]+(?:\s*=\s*(?:[^\s"'=><`]+|'[^']*'|"[^"]*"))?)* (?:\s+charset(?:\s*=\s*(?:([^\s"'=><`]+)|'([^']*)'|"([^"]*)"))?) (?:\s+[^\s"'>/=]+(?:\s*=\s*(?:[^\s"'=><`]+|'[^']*'|"[^"]*"))?)*\s*/?>|$1$2$3|i ぐらいか でもこれ後で読むのしんどいでしょ ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる