Regular Expression(正規表現) Part14 [無断転載禁止]©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
Regular Expressionスレです。 質問する場合は必ず実装言語や処理系ソフトウェア名を示してください。 前スレ Regular Expression(正規表現) Part13 http://echo.2ch.net/test/read.cgi/tech/1415149975/ 次スレは>>980 宜しく 天ぷら等2以降 >>392 ここでドメイン名文字種チェックせにゃならんの IPアドレスではないで判断でけんの >>397 現仕様だとまさにIP除外なんだけど、123.comとかが入ってくるので、あとで除外しているという。。 >>396 今日、やっと開発場所で試しました。 ドメインは見事マッチしました!が、 △△domain:△hogehoge.com改行 の行までマッチしてしまうので、 ^\s* (?:[A-Za-z]〜 のところを ^\shostname:* (?:[A-Za-z]〜 にしてみましたが、今度はすべてマッチしなくなりました。 スペース連続shostname:*を除外したつもりなんですが…教えてくだされ。 ^[△]*hostname:[△]*([0-9.]*[A-Za-z\-][0-9A-Za-z.\-]*)$ ^[△]*hostname:[△]*([0-9.]*[^\s0-9.]\S*)$ hostname:△mevius.5ch.net hostname:△86886.jp hostname:△日本語.jp hostname:△はじめよう.みんな >>398 要件は満たしたつもりだが, その行がマッチしちゃならん理由は? それともキャプチャの意味が分かってないのか? >>398 あと申し訳ないけど, 正規表現を全く理解してないよね? 何でその書き換えで除外出来たと思ったのか教えてくれる? あぁ, hostnameは固定文字列なのか なら ^\s*hostname:[^\S\x0A\x0D]*((?:[A-Za-z](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?\.)*[A-Za-z](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)$ だけど 正規表現の書き方教えてください。 CentOS 7のサーバーにURLを要求した際、下記のような余計な文字が付きます。付くことがあります。 /ディレクトリ/ファイル名.拡張子%01 /ディレクトリ/desktop.inib%01 /ディレクトリ/desktop.inie%01 またファイル名の後に、 %EE%81%9F%E2%81%80%EE%81%97%C9%84とか %E6%89%B8%E7%A8%B7%E4%99%BA%E5%A5%97%E3%8D%95%E4%BD%8C%E6%A1%B2%01とか ファイル名の語尾に不特定の文字が勝手に付く場合もあります。 ディレクトリを要求したときも ディレクトリの語尾に%E4%84%B7など(これも不特定)が付いてしまうことがあります。 これを除外するには、 正規表現でどのように書けば良いのでしょうか? よろしくお願いします。 あと忘れてたけどWebDAVならクライアントにWinSCP使うとか ありがとうございます。 自分の場合「空」にはなってませんが似てますね。 便利なクライアントアプリケーション探してみます。 pattern = /^(.*)(?!%)/ p pattern.match('abc%123') Ruby で否定先読みを使ったら、「abc」だけ取れない。 すべての文字列にマッチしてしまう なんでやねんw なんでやもなにも、.* だから全体にマッチするよ。1文字ごとにチェックするか、文字クラスを使いなさい。 Ruby では、先頭から、% を探して、それ以降を削除する str = '/dir/desktop.inib%01%EE%81' pos = str.index('%') if pos str = str.slice(0...pos) end puts str 結果 /dir/desktop.inib 正規表現でも、できた。 Ruby では、先頭から、% 以外の文字を探す pattern = /^[^%]+/ str = '/dir/desktop.inib%01%EE%81' puts pattern.match str 結果 /dir/desktop.inib 要件には書いてないけど, .iniまでが正しいファイル名だと思うよ その後ろのbとかeもゴミ どういう法則性でb,eが付いたのかがわからないと、 b,eの他にも付くのがあるのか、また付かないこともあるのかもわからん 例えば、hoge.exee%01とかになるのか? 皆さんありがとうございます。 >>412 それ以外にも幾つか変な文字の時もあり、 問題なく何も付かない時もあります。 決まったパターンは無いと思った方が良いですね。 すべてが1byte文字の時は 最後に変な文章を残してしまいました。 すべてが1byte文字を要求するときは、 そんな変なゴミは付きにくいと書こうと思ったのですが、 まだ確証が無いので無視して結構です。 ●Regular Expressionの使用環境 桜エディタ(テキストエディタ) ●検索か置換か? 置き換え ●説明 文字数、文字種はいろいろです。ただしすべて半角(1バイト文字)です。 結果として、<>内の文字だけにできればどんな方法でも構いません 必要な情報かわかりませんが、<>の外には、<>があることはありません。 asqa>w3e<a>s98<as897kja> ←こんな感じの行はありません。 行末は必ず、>で終わり、必要な文字は必ず<>でくくられたものの中にあります。 いらない文字<必要な文字>ここに改行が入る という書式は絶対です。 ●対象データ R&^&*(!TYUIKM<slihfd> BA%(*&%ASAS<asdlikh> TF^(VB(*&N<a09sfyighkljn> ●希望する結果 slihfd asdlikh a09sfyighkljn よろしくお願いいたします。 >>416 ありがとうございます。うまく抽出できました。 このぐらいの正規表現なら基本だし, 覚えると正規表現の載ってるエディタでの編集が楽になるよ とりあえずPerl互換を勉強してみるといい C#なんですが [ああ]おおおおお [いいい]こここここ [うう][ええ]そそそそそ ととととと[たた] ↓ おおおおお こここここ そそそそそ ととととと[たた] にしたいんですが、どうしたらいいでしょうか。 ※先頭じゃない文中の[はは]は残したい \[[^\]]*?\](?!$) ところによっては\[[^\]]*?\](?!(?:\n|$)) マルチラインモード ^(?:\[([^\[\]])\1*\])+ マッチ部分を除去 >>424 文中は消えていいんじゃない? >>420 に > [うう][ええ]そそそそそ > そそそそそ ってあるし あ、 > ※先頭じゃない文中の[はは]は残したい この[はは]はマッチしたらダメなのか これ例の中においてくんないかなー というか定義がよくわからんちん ^\[.*\](?!$) ところによっては(?<=(?:^|\n))\[.*\](?!(?:\n|$)) マッチ [ああ]おおおおお [いいい]こここここ [うう][ええ]そそそそそ [たた]ななはは[まま]やや →[たた]ななはは[まま] [たた]ななははまま[やや] →[たた] アンマッチ ととととと[たた] ちち[はは]ぱぱまま >>425 [たた]ななはは[まま]やや の[まま]を含めずマッチしたい([たた])ならかなり複雑になりそうでちょっといますぐは思いつかないや それってつまり 行頭[ 行頭から括弧が繋がり、且つ、行末]を含めない範囲 なら [たた][なな][はは][まま][やや] のマッチが →[たた][なな][はは][まま] でいいのか、それとも行そのものがアンマッチなのかよーわからんし >>425 カッコ内も同じ文字が重なるように読めるしなー まぁこういう仕様をちゃんと書けるならそもそも正規表現で困らんのだろうけど orz... 試したら確かに >>422 だと先頭が残りますネ すみません [ああ]おおおおお → おおおおお [あああ]おおおおお → おおおおお [ああ][いい]おおおおお → おおおおお あああああ[いい] → あああああ[いい] あああ[いい]うう → あああ[いい]うう です。 先頭付近の [] は消したいけど、それ以外は残したい、って風です。 >>429 [たた]ななはは[まま]やや は? [たた][なな][はは][まま][やや] はどーなんの? [あいう[かきく]たちつ] [あいう[かきく]]たちつ とか括弧内包の場合どーなんのとかも あと行末も係わるんだから、例の同じ行に余計な文字列入れないで(たぶんこの件では大過ないと思うけど) >>430 内包無視するとしたら (?<=^)(?:\[[^\[]*?\])+(?!$) ところによって(?<=(?:^|\n))(?:\[[^\[]*?\])+(?!(?:\n|$)) かね >>429 を満たし、 [たた]ななはは[まま]やや →[たた] [たた][なな][はは][まま][やや] →[たた][なな][はは][まま] となるし たぶん 行頭[ および 行頭[に対応する]までマッチ 行頭[ および 行頭[に対応する]から括弧が繋がり、且つ、行末] および 行末]に対応する[までを含めない範囲 あたりなんだろうなー ぱっと思いつくのはちょめちょめしたダウンロードファイルのリネームをしたいようなかんじかね 正規表現の使いどころってどんなところですかね? 普通レベルのプログラマから見ると可読性低くて保守性も悪い気がする タグの要素を最初にバッと配列に入れやすいとか? >>433 可読性低くて保守性も悪いっていうのは本当にその通り プログラミングで使うならまずは(正規表現が非常に直感的でない限りは)正規表現以外の選択肢を考えるべきで, それが可読性や保守性を上げないとなった上で正規表現が選択されるのがよい 勿論保守性や可読性を気にしないワンライナーとかであれば気にする必要はないが あとはエディタやgrepなんかだと他に有力な選択肢がないから正規表現になる 単純に、 (?m)^\[.*\](.*) じゃだめなん? >>435 全然ダメ 入力が [abc]def[ghi] なら全文がマッチする(量化指定子*はgreedyだから末尾手前まで全部食う) >>433 実行環境によってだけどコンパイルされて速くなったりするので さくっと一行で書けるならメリットはあるよ プログラム書いた方が良い場合もある ケースバイケース >>434 >>437 レスサンクスコ 今Pythonで作られているパッケージを保守してるんだけど、お約束のように最初に正規表現で抜いて後で編集してる 最初のパフォーマンスを考慮してるのかもだけど、読みにくくて一般人にはいいことないよ >>433 ワンライナーで可読性保守性とか気にしない ストリームエディタで検索、ログの抽出が最たる用途じゃないか >>420 $# 「行頭部分にある 1 個以上の \[[^\]*\] を削除」と初見で思ったのだが、違うのか? $# それとも C# でどうやるかわからないという話? 申し訳ないが C# は知らない。 $ $cat a_in [ああ]おおおおお [いいい]こここここ [うう][ええ]そそそそそ ととととと[たた] [ええ]あああ[いい]うう $perl -pe 's/^(\[[^\]]*\])+//' < a_in おおおおお こここここ そそそそそ ととととと[たた] あああ[いい]うう $perl -0777 -pe 's/^(\[[^\]]*\])+//gm' < a_in おおおおお こここここ そそそそそ ととととと[たた] あああ[いい]うう $ >>436 Non-greedy(最短)なマッチ使えばいいだけじゃね? 使えない環境なの? >>441 none-greedyじゃ先頭しかマッチしない [abc][def]ghi の[abc]しか除去出来ない 反復適用すればいいというならその通りではあるが [ab][cd][ef]ああ これは、繰り返しが入っている。 N回削除する必要がある [ab][cd][ef]ああ [cd][ef]ああ [ef]ああ ああ [〜] でグループ化すべき /^\[[^\]]*\]/ =~ "[ab][cd]ああ" $& #=> [ab] Ruby で書いた。 行頭が\[ で、\[ 以外の文字が、0以上続いて、\] がある /^\[[^\]]*\]/ =~ "[ab][cd]ああ" $& #=> [ab] $' #=> [cd]ああ /^\[[^\]]*\]/ =~ $' $& #=> [cd] $' #=> ああ /^\[[^\]]*\]/ =~ $' #=> nil Ruby で書いた。 行頭が\[ で、\[ 以外の文字が、0以上続いて、\] がある $& はマッチした部分で、$' はマッチした部分の後ろを表すから、 マッチを繰り返していけば、出来るけど /^(\[[^\]]*\])+/ =~ "[ab][cd]ああ[ef]" $& #=> [ab][cd] やったー。Ruby で出来た \[ があり、\[ 以外の文字が、0以上続いて、\] がある。 これをグループ化して、1回以上繰り返す ただし、グループ外に、先頭からを指定する 正規表現で使用される記号があるとワケわからなくなってくるから 適当な記号、例えばQなどに置き換えて試行錯誤して最後に元の記号に戻したりする 余計なバックトラックを防ぐために $s = qr/(?>\s*)/ ってやってパターンに埋め込むことならある。 (?s:^(?=.*ス)(?=.*プ)) CHmateで使う正規表現らしいんだけど最初の (?s:" の意味が検索してもわからないのですが教えていただけないでしょうか >>451 ありがとございます 確認してなんとなく分かりました ところでこの正規表現の場合(?s:)って名前には改行はないので不要じゃないかと思ってしまうのですがどういう目的で使われているのでしょうか 書いたヤツの趣味じゃ? しかもかなりてきとう ワッチョイ名前ならおそらくドコモ判別?でもプだけではないhttp://itest.5ch.net/test/read.cgi/mango/1467623805/312 先読みなんてコストかけなくてもKOROKORO AAはSd固定 改行を無理矢理入れ込んでというシチュエーションでスとプでねらい打ちも違和感 本文で^(?=.*A)の類を使うとレス数後半のコストはかなりのもの これは名前だから大したことにはならないけど 深謀遠慮があるのかも知れんがそれこそ書いた本人へ C#で、 var rgx = new Regex("(.)+"); var str = "こんにちは。"; Console.WriteLine(rgx.Replace(str, "$1")); とすると「。」が出力されるのですが、なぜですか? $1は「。」になるのですか?「こ」だと思ったのですが、違いますか? どれどれ… javascript 'こんにちは。'.replace(/(.)+/, '$1'); => "。" ほんまや!知らんかった >>455 配列に入れてくれればいいのに って思ったことあるわ 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 とか、構文解析ツールが必要 それらを使って出力された、抽象構文木を使うのがよい ★タイトル ★★タイトル 上のものにマッチさせたいのですが、 ^★.*$ としてしまうと、下まで含まれるのですが、どうしたらいいでしょうか ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる