• ベストアンサー

3回以上連続する文字(どんな文字でも)を削除する方法

3回以上連続する文字(どんな文字でも)を削除する方法 お世話になります。 掲示板等の文字列で、、、 ■■■■■■■■ や ========= といった連続する文字列を削除したいと思っています。 その際「3回以上、同じ文字がつづいているものは、根こそぎ削除」という形にしたいと思い、 ~s///g; を用いて、あれこれやっているのですが (また、ぐぐって、あれこれ調べたのですが) 全く、うまくいきません。 どの様にすれば、うまくいくのか、アドバイスいただければ幸いです。

質問者が選んだベストアンサー

  • ベストアンサー
  • ryu_chan
  • ベストアンサー率37% (69/186)
回答No.3

No.2のTacosanがおっしゃるように、decode、encodeをするのが正攻法だと思います。 use utf8 の代わりに use encoding 'cp932' という方法もあるかもしれませんが、これは超非推奨なのでやめたほうがいいでしょう。 Shift-JIS限定なら以下の正規表現でいけそうな気もします(あまり自信なし)。 $moji =~ s/([\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])\1\1+//g;

keeeeeeen
質問者

補足

ryu_chanさん、アドバイスいただき、ありがとうございます!! >Shift-JIS限定なら以下の正規表現でいけそうな気もします(あまり自信なし)。 実は、今一度確認してみたところ、てっきり、Shift-JISエンコード保存だと思い込んでいた、融合させたい私の既存プログラム書類は、「日本語(MacOS)エンコード」という、独特な?(Shit-jisの亜種?)エンコードで保存されている事が分かりました。(^_^;) で、このエンコードの場合、「\」は使えず「¥」で表現する様になっており、上記書かれているものを、¥に変換した、、、 $moji =~s/([¥x00-¥x7F¥xA1-¥xDF]|[¥x81-¥x9F¥xE0-¥xFC][¥x40-¥x7E¥x80-¥xFC])¥1¥1+//g; で、うまくいきました!! ありがとうございます! (どこかのサイトで、「¥」は使うべきではない!という記述を見かけたことがあるのですが、、、、w) で、上記式は、sara9647さんが提示されている「s/(.)\1\1//g」の「(.)」の部分に、「([\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]」を当てはめたものなのですね。 で、ぐぐったところ、「\x00-\x7F\xA1-\xDF」は1バイトSHIT-JIS文字、「[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])」は2バイト SJIS文字ということが分かり、このどちらかの文字クラスの3回以上の連続にマッチした場合、削除する、というやり方の様ですね(解釈が間違っていたらご指摘下さい) とした場合、sara9647さんが使われている「(.)」の意味も知っておきたいのですが、いくら、ぐぐっても、これが分かりませんでした(グーグルは、こーいった記号のみの検索で威力が発揮できない様で、、、、「Perl (.) マッチ 」でも、何もひっかかってきません。。。 私のPerlメモ帳(備忘録)には、、、、 「.* 」が、何かの文字列にマッチさせたい時に使うものとあり、 「([^<]*) 」が、どんな複数の文字列でもマッチさせる時に使うもの、とあります。 ですので、てっきりsara9647さんの式は、、、 s/(.*)\1\1//g だと思っていたのですが、実際は、、、 s/(.)\1\1//g なのですね。 できましたら、その理由などもご教授いただければ幸いです。 ※尚、ryu_chanさんのプログラムと、その表示結果を以下記しておきます。 ----------------------------- #!/usr/local/bin/perl print <<"HTML"; Content-type: text/html <html> HTML $moji="aiiuuueeeeoooooooooooo"; $moji =~s/([¥x00-¥x7F¥xA1-¥xDF]|[¥x81-¥x9F¥xE0-¥xFC][¥x40-¥x7E¥x80-¥xFC])¥1¥1+//g; print $moji."<br><br>"; $moji="あいいうううええええおおおおおかかかかかかかかかかかかか"; $moji =~s/([¥x00-¥x7F¥xA1-¥xDF]|[¥x81-¥x9F¥xE0-¥xFC][¥x40-¥x7E¥x80-¥xFC])¥1¥1+//g; print $moji."<br><br>"; $moji="★★■■■□□□□◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆"; $moji =~s/([¥x00-¥x7F¥xA1-¥xDF]|[¥x81-¥x9F¥xE0-¥xFC][¥x40-¥x7E¥x80-¥xFC])¥1¥1+//g; print $moji."<br><br>"; ----------------------------- 表示結果 ----------------------------- aii あいい ★★ ----------------------------- ※3文字以上のものは「根こそぎ」削除される理想のプログラムでした。 (ryu_chanさん、重ね重ね、教えていただき、ありがとうございます!)

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

えぇと.... まず正規表現で「.」は「任意の 1文字」にマッチします (改行にマッチするかどうかは状況による). で, 任意の正規表現のうしろに「*」を付けると「直前のものが 0個以上ある」という意味を持ちます. なので, 「.*」で「『任意の 1文字』が『0個以上ある』」, つまり「(0個以上の文字からなる) 任意の文字列」にマッチするわけです. でもって, 正規表現をかっこでくくると「後で使うかもしれないからその中のものを覚えておく」という働きもあります. 全体で「(.)」だと「任意の 1文字にマッチして, それを記憶する」ということになります. この「記憶しておいたもの」を*パターン中で*使うときに「\数字」という形を使います. ここの「数字」は「最初からかぞえた開きかっこの数」に対応します. 置換文字列 (s/// のうしろのところ) で使うときは, 「$数字」の形で参照します. と, 正規表現は「簡単なものを組合せて複雑なパターンを作る」ようになっています. なので, 「* がどういう意味を持つのか」「() はどういうときに使うのか」というように理解すべきです. 備忘録のように 「.* 」が、何かの文字列にマッチさせたい時に使う、 「([^<]*) 」が、どんな複数の文字列でもマッチさせる時に使う などとしてしまうと応用がききません.

keeeeeeen
質問者

お礼

詳しく教えていただき、ありがとうございます!!! >応用がききません. もう、おっしゃるとおりで。。。。(^_^;) 昔、少しだけかじった事のあるBasic言語の類推で、掲示板プログラムのちょっとした改造から始め、最近は、各種APIを活用したウェブサービスも、改造、改造で作れる様にはなったのですが、なにせ、手におえない状況になった時に、その都度、ぐぐって(それでも手に終えない時に、ここにお世話になっています)解決策を探る、という手法でやってきたので(Perlの本も3冊買って読んだのですが、具体的に取り組まないと頭に入ってこなくて(つまり、基礎の基礎があまり身についていない))、おっしゃるとおり、応用が効かず、その都度の対応策をPerl備忘録に書き込み、その場をしのいできました。 >正規表現は「簡単なものを組合せて複雑なパターンを作る」ようになっています なるほど。。。。。 今まで、例えば「([^<]*)」等という表現を見るにつけ、その見た目だけで、これはもう、自分の頭を超える手法だ!と直感的に思い込み、基礎を頭に叩き込もうとせず、その都度、その都度の具体的な処理例ばかりおいかけてきたのですが、今一度、「簡単なもの」「基礎の基礎」を頭に入れてみようと思いました。 ご指摘、本当にありがとうございます! とゆーことで、今日、教わった基礎的な事を、ここに記させていただきます。 ●「.」は「任意の 1文字」にマッチする。 ●正規表現をかっこでくくると「後で使うかもしれないからその中のものを覚えておく」という働きがある。 ●正規表現は簡単なものを組合せて複雑なパターンを作る様になっている。    (基礎的なもの、簡単なものは記憶すべし) ●入力時の文字コードに合わせた処理をしないと、動くものも動かない。 それにしても、いろいろとアドバイスをしていただいた、sara9647さん、Tacosanさん、ryu_chanさん、本当にありがとうございました! 心より感謝致します。

全文を見る
すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

入力ファイルが shift_jis なら, Encode::decode を使って Unicode にすればいいんじゃないかな. 出力の際に Encode::encode する必要はあるかもしれん. マッチパターンの「\1」は「最初の開きかっこの部分にマッチした文字列」を意味します. これだけわかれば (.)\1\1 で「同じ文字が 3回続いている」ことがわかるかとおもいます... あれ? 3回「以上」なら (.)\1\1+ か? あと, 「~s///g;」じゃないからね. この「~」はその前にある演算子 (=~ や !~) の一部なので切り離しちゃダメ.

keeeeeeen
質問者

お礼

>マッチパターンの「\1」は「最初の開きかっこの部分にマッチした文字列」を意味します. なるほど。そーゆーことでしたか。 納得しました。 ご教授いただき、ありがとうございます。  (改めて、Perlの奥深さに、感嘆しています。 また、「同じ文字が 3回以上続いているものを削除」という、少しだけやっかいな処理をしなければならない様に見えるものを「s/(.)\1\1//g;」等というシンプルな表現で処理できてしまうPerlの懐の深さ?も、改めて感じました。Tacosanさん、面白さを教えていただき、ありがとうございます) >「~s///g;」じゃないからね. この「~」はその前にある演算子 (=~ や !~) の一部なので切り離しちゃダメ. $moji=~s/(.)\1\1//g; は、いいけれど、 $moji=~ s/(.)\1\1//g; はダメ、ということでしょうか。 今まで、ずっと「~s///g」を1つのセットだと思い込んでいました。。。。 Perlの基礎知識を補正していただき、ありがとうございます!

keeeeeeen
質問者

補足

※訂正 $moji=~s/(.)\1\1//g;   は、いいけれど、   $moji=~ s/(.)\1\1//g; は駄目 ではなく、、、 $moji=~ s/(.)\1\1//g;   は、いいけれど、   $moji= ~s/(.)\1\1//g; は駄目

全文を見る
すると、全ての回答が全文表示されます。
noname#169205
noname#169205
回答No.1

s/(.)\1\1//g 但し文字コードには注意 use utf8なりuse encoding ""がないと所謂全角文字に関して処理が出来ない。

keeeeeeen
質問者

補足

アドバイス、ありがとうございます!! ●use utf8宣言し ●プログラム書類自体をutf8エンコーディングで保存した上で ●s/(.)\1\1//g を走らせたところ、見事に3文字以上のものが削除されました! ありがとうございます! その上でのことなのですが、、、 ●「shiftjis」エンコーディングで保存されているプログラムファイルに組み込む場合は、どうしたらよいのでしょうか?(組み込みたいプログラム書類自体が既に「shiftjis」エンコーディングで保存されている上に、この設定を変更できない(変更すると、うまく稼働しなくなります)、こんがらがった状況になっています) もしくは、「shiftjis」エンコーディングで保存されているプログラムファイルでは、原理的に実現不可能なことでしょうか?(尚、サーバーのperlのバージョンはver.5.8.* です) ●s/(.)\1\1//g のどこにも「3」という数字が入っていなのですが、どうして、これで「3回以上の文字のみ」マッチさせる事ができるのでしょうか?(実際に、おっしゃるとおりに稼働したので驚いています。理由を調べてみたのですが、分かりませんでした、、、) 尚、私がテスト的に走らせたプログラムは以下です。 (実際に、組み込みたい「shiftjis」エンコーディングで保存されているプログラム書類は、これとは別にあります(^_^;)) --------------------------------- #!/usr/local/bin/perl use utf8; print <<"HTML"; Content-type: text/html <html> HTML $moji="aiiuuueeeeoooooooooooo"; $moji=~s/(.)\1\1//g; print $moji."<br><br>"; $moji="あいいうううええええおおおおおかかかかかかかかかかかかか"; $moji=~s/(.)\1\1//g; print $moji."<br><br>"; $moji="★★■■■□□□□◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆"; $moji=~s/(.)\1\1//g; print $moji."<br><br>"; --------------------------------- 結果 --------------------------------- aiie あいいえおおか ★★□ ---------------------------------

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 記号とあらば、1文字でも全て削除する方法(記号全滅作戦)

    記号とあらば、1文字でも全て削除する方法(記号全滅作戦) お世話になります。 先日、、、、 http://okwave.jp/qa/q6246444.html で、3文字以上つづく文字を根こそぎ削除する方法について助けていただきました。 (ありがとうございました) この様な事をしたい背景としましては、記号等が20文字程以上つづくと、TABLEの表組の中で、それらの連続文字が「改行されず」、ぺージのレイアウトをメチャクチャにするからなんです。 (同じ悩みを抱えている方も少なからずいるのではないかと思うのですが。。。) そこで、3文字以上の文字が連続するものは、根こそぎ削除!という、先日教えていただいた方法の導入により、この問題は解決するだろうと、心安らかな日々を送っておりました。 が、今日になって。。。 ∴▼△▼∴△▼△∴▼△▼∴△▼△∴▼△▼∴△▼∴ ★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆ 等という記号の(1文字おき、2文字おき)連続が某APIから吐き出され、それを表示している私のサイトのレイアウトが例によって、むちゃくちゃになっておりました(泣)。 そこで、解決策としては、、、 ●記号とあらば、1文字でも、根こそぎ削除(但し、日本語の句読点、英語のピリオド等は除く) もしくは、、、 ●1文字おき、2文字おきでも、そのパターンが3回以上連続する文字列の場合は、それらを根こそぎ削除 を思いつきました。 後者につきましては、そのマッチさせる手法を想像する事すらできないので(泣)、前者について、あれこれググッてみたのですが、これまた、どんぴしゃりのヒントを得る事ができませんでした。 ※削除したいものは「シフトJIS 第1水準漢字コード表の中の記号群」なので、 http://crocro.com/pc/write/hide/chimarl09_02.html#02 こちらのコードでマッチさせればよいのかと思ったのですが、コード表記が 「8140~81FF」 となっており、先日教えていただいた [¥x81-¥x9F¥xE0-¥xFC] 等とは表記が異なる為、適応できません。(^_^;) ということで、SJISの憎き記号達(但し、日本語の句読点、英語のピリオド等は除く)を削除する(マッチさせる)手法について、アドバイスいただければ幸いです。 ※ちなみに、、、、 $contents=~s/★//g; $contents=~s/☆//g; は効果あるのですが、何故か、、、、 $contents=~s/△//g; $contents=~s/▼//g; は効き目がありませんでした。(^_^;) (そこで、文字コードで範囲を指定して根こそぎ削除を狙っています)

    • ベストアンサー
    • Perl
  • 文字列が連続しているかどうか調べたいのですが、良い方法はないでしょうか

    文字列が連続しているかどうか調べたいのですが、良い方法はないでしょうか? ExcelVBAです。 例えば"abc12saaa"などと文字列があって、4文字以上同じ文字が連続したいるか、4文字以上順番になっている文字があるかを調べるにはどのような方法があるでしょうか。 順番になっている文字とは"abcde"とか"1234"のようなものです。 1文字ずつ取り出して比較したり、1文字ずつAsc関数で数値化すればできるとは思いますが、スマートな方法、既存の関数とかないでしょうか。 よろしくお願いします。

  • perlでの入れ子文字列削除

    perlを利用して文字列処理を行う際に、入れ子になった文字列を削除したいのですが、正規表現のうまいやり方が思い浮かびません。 例としましては 今日は雨(雪ではない(この辺の処理に困っている))が降っている。 という文章を 今日は雨が降っている。 と処理できるようにしたいです。 $data =~ s/(.*?)//g; $data =~ s/)//g; というやり方では、3重以上になった時の処理ができません。 できれば何重になっても可能な方法をご教示ください。

    • ベストアンサー
    • Perl
  • 2回以上繰り返される文字列の削除について

    以下の文字列(置換前)で、-aaa について複数存在しているので、 最初の -aaa を残して残りの -aaa をすべて削除したいと考えています。 1回の正規表現+置換で行いたいのですが、どのようにいすればよいでしょうか? 【置換前】 -bbb -aaa -ccc -aaa -ddd -eee -aaa -fff 【置換後】 -bbb -aaa -ccc -ddd -eee -fff ちなみに、複数回の正規表現+置換を使ってよい場合は、 while (m/( -aaa.*) -aaa/) { s/( -aaa.*) -aaa/$1/; } でできると考えています。(動作確認まではしていないので間違ってるかも)

    • ベストアンサー
    • Perl
  • 2つ以上の連続する空白文字を除去

    フォームから受け取った値の中の2つ以上の連続する空白文字を削除したいのですがどうすればいいでしょうか。 一つは区切り文字として残したいのです。 調べてみたところ splitで正規表現するとできる というサイトを見たのですが具体的に書かれていなかったのでよくわかりませんでした。 わかる方お願いします。

    • ベストアンサー
    • PHP
  • 正規表現で2回以上連続する文字にHITさせたい

    パスワードの入力で aa や 11 など 2回以上連続する文字を入力したらHITさせてはじきたいんですが どういう正規表現を書けばよいでしょうか /.{2,}/ としたのですが 結局二文以上あれば何にでもHITしてしまいます /a{2,}|b{2,}|c{2,}・・・/ みたいなのを スマートに書く方法はありませんか

    • ベストアンサー
    • Perl
  • Excel 特定の文字列が連続で続いたら非表示

    セル内の特定の文字列が2個以上連続してる場合、連続している文字列を非表示にしたい。 セルに横一列にデータを入力し、=C2&","&D2&","&E2&","& ,,,,, 横の列にはデータを","を入れて文字列を結合したセルを表示させます。 例 データの文字列が1 2 3 4 5と入力されていたら 1,2,3,4,5,,,, と表示され複数セルの入力された文字列が結合した形で表示されます。 これを 1,2,3,4,5 とカンマ","が2個以上連続したらデータの(この場合5)後ろの連続しているカンマを非表示にしたいです。 Excelは2016で、使用できる関数が限られています。 この場合、他の関数の組み合わせで1,2,3,4,5と連続するカンマを非表示にする方法はありますでしょうか。 Excelのシートは添付画像の通りです。 詳しい方いましたら、ご教授下さい。 よろしくお願い致します。

  • 1キロバイト文字の削除について

    例えばsijisの「、」を削除しようと思い $body =~ s/\xa4//g; とすると\xa4を含む「う」などにも作用し、\xa4を削除してしまいます。 そこで2キロバイトの文字には作用しないようにするにはどうしたらいいか考え 「う」などがあった際には\xa4を削除しないようにしたのですが その場合、例えば「う」と「、」の両方があった時に「、」を削除しなくなってしまいます。 1キロバイトの文字を削除しても2キロバイトの文字には影響しない 何かいいアイデアはないでしょうか?

  • 文字連続の検出手段

    ある文字列を調べ、 その中で"同じ文字が10連続以上続いている部分"があるかどうかを検出したいのですが、 プログラム慣れしていないもので相当梃子摺っています。 どのように記述すれば良いのでしょうか。

    • ベストアンサー
    • Perl
  • 2文字以上の重なっている文字列を抜き出す方法

    例えば、次のようなテーブルがあって、mojiretuカラムにおいて 他の行の文字列と2文字以上の重なっている部分の文字列を取得したいのです。 ただし条件があって下の場合だと、「ab」は1、2行目で重なっているのですが、 2行目の「ab」はそれで全ての(終結している)文字列なのでマッチさせないようにしたいです。 なので、このテーブルから取得したい文字列は 「cd」「bcd」「abc」「bc」「de」になります。できれば重なっている回数も含めて取得したい (「cd」2回、「bcd」1回、「abc」1回、「bc」1回、「de」1回、) のですが、どのようなSQLを記述すれば良いのでしょうか? [テーブル] mojiretuカラム abcd ab cde abcde xy

    • ベストアンサー
    • MySQL
このQ&Aのポイント
  • キヤノン製品の下取り登録方法を教えてください。
  • 下取りプリンタの登録手順についてお知りになりたいです。
  • キヤノン製品の下取りに関する登録方法を教えてください。
回答を見る