質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

sed

sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Q&A

解決済

2回答

6365閲覧

sedで範囲内を正規表現で置換、その他は引き継ぐ。

seel

総合スコア25

CentOS

CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

sed

sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

0グッド

0クリップ

投稿2016/09/28 06:49

編集2016/09/28 21:53

これの関連する質問をいくつか質問していまして
ややこしく思う方へもすみません。

なんと表現したらいいのかよくわかっていないのですが

sample.html

<h1>テキストABCABC123123テキスト</h1> <h2>テキストABCABC123123テキスト</h2>

処理する部分は

<h1>テキストABCABC123123テキスト</h1>

処理する内容は

大文字小文字半角全角英数字だけを削除する

正規表現の内容 小文字半角全角英数字だけ

(間違っているかもしれませんが)

[a-zA-Za-zA-Z0-90-9]

前後の文字列はそのまま残します。

主に使う書式は

sed 's///g' あるいは

sed 's|||g' (エスケープ回避)

書いてみると

sed 's/<h1>[a-za-z0-90-9]</h1>/<h1></h1>/g'

これでは多分ヒットしない そのまま置換されてしまう。

sed 's/<h1>(.)[a-za-z0-90-9](.)</h1>/<h1>/(.*)</h1>/g'

正規表現の前後に (.*) をつけてみてもできませんでした。

これはもしかして後方参照というものを使うのなら
それは正規表現の後ろの部分だけが該当するのでしょうか

やりたいことはsedをつかってHtml内の指定タグ範囲内で
正規表現指定文字列部分にある処理をすることです。

sedで <h1></h1>内 に 削除する文字列を正規表現で指定して置換(削除))することです。

例えばawkとかもっといい方法があるのかもしれません、自分でやってみてできなかったので
アドバイスお願いします。


訂正を兼ねた補足です。まとまらなくて申しわせありません。

あとで気がついたのですが下記の<h1></h1>部分で
text部分のみへの適応が目的であると気が付かせていただきました。
思っていたよりも複雑なことをやろうとしておりましたのですみません。

sample_d.html <h1><a href="http://exmple.com/">text</a></h1>

このtext部分に様々な形態の文字列があります。

その中の大文字小文字半角全角英数字を削除したいと思います。
なのでそれを正規表現で指定したいと思います。

[a-zA-Za-zA-Z0-90-9]

これをsedでやろうとしています。
教えて頂いたも含めて書いてみます。

sed 's/<h1>/(.*\)[a-zA-Za-zA-Z0-90-9]\(.*\)<\/h1><h1>/\1\2</h1>/g'

ここで言う/\1\2部分は前半部分の/(.)が/\1で後半部分の/(.)が\2になり

正規表現部分が消えて残りの部分が残るというとこでしたらそれでいい思います。
ただそのtext部分にはランダムに様々な文字列が入っていますので
この/\1\2部分以外の正規表現部分該当箇所が<h2></h2>内に複数ランダムにある場合は
すべて拾ってくれるかという疑問があります。私が無理にワンライナーでやろうとしてることはわかっています。
スクリプトを組むべきかとも思います。

実はカレントディレクトリ内すべてのファイルにこの処理をしたくてこの質問をしておりました。

bash

1find . -type f | xargs sed -i 's/<h1>/(.*\)[a-zA-Za-zA-Z0-90-9]\(.*\)<\/h1><h1>/\1\2</h1>/g'

これだと<h1><a href="http://exmple.com/">部分まで該当してしまいます。

補足2

[a-zA-Za-zA-Z0-90-9]
は1文字しか該当しないようでいままでそれに気が付きませんでした。

補足・修正をさせていただきました。
ご指摘ありがとうございます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

htsign

2016/09/28 06:50

余計なお世話かもしれませんが、h1タグが閉じていませんよ。
seel

2016/09/28 06:53

ありがとうございます。
otn

2016/09/28 08:15

「大文字小文字半角全角英数字だけを削除する」と書いていながら、次の行からは小文字のみになっていますが、どちらが正しいのですか?
seel

2016/09/28 08:21

そうですね、間違いです、ご指摘ありがとうございます。
otn

2016/09/28 08:45

どちらかが間違っているのは自明なので、どちらが間違ってるのか書かないと意味がありません。質問本文を正しく書き直して下さい。
seel

2016/09/28 11:05

小文字のみになっているのが間違いです。訂正をしました。
guest

回答2

0

前のご質問の続きだと思います。

ご自分の質問に寄せられた回答を読むことによって、新しい疑問がわいてくる、ということはあると思います。ですから、その新たな疑問についてあらためて質問をされることはかまわないです。
ですが、前の質問でも寄せられた回答によって一部の疑問は解決しているわけですから、まずはそちらをちゃんと解決済みにしてください。それからあたらしい質問をしてください。

ともあれ、答えます。


s/<h1>[a-za-z0-90-9]<\/h1>/<h1><\/h1>/g

ここで [...] で囲まれたものは、そのうちの1つにマッチします。また「*」などが後ろについていませんから、1回だけ出現し、繰り返して出現することはありません。

ですからこの場合、

  • 「『<h1>』と『</h1>』の間に数字が1文字だけあるとき、『<h1></h1>』にする」
    簡単に言うと、「数字が1文字だけあるときに取り除く」

という意味になりますね。


次に、もうひとつのほうです。このような文を書いていらっしゃいます。

s/<h1>\(.*\)[a-za-z0-90-9]\(.*\)<\/h1>/<h1>/(.*\)<\/h1>/g

「(...)」は、マッチした箇所をグループ化します。また、あとで後方参照 (「\1」、「\2」等) で参照できるようにします。つまり、置換結果のほうに書くべきなのは、グループではなく広報参照です。

ですのでやりたいことは、こういうことではないでしょうか。

s/<h1>\(.*\)[a-za-z0-90-9]\(.*\)<\/h1>/<h1>\1\2<\/h1>/g

まずパターンのほう (「s///g」の中の左側) を見ると、次のような意味になっていますね。

  • 「『<h1>』と『</h1>』の間に、ひとつめのグループとして任意の文字が0文字以上、次に英数字が1文字だけ、次にふたつめのグループとして任意の文字が0文字以上ある」。
    -- 理解できていますか? 上の説明でわからなければ、sedのマニュアルをよく読んで、正規表現の書きかたを理解してください。

次に置換結果のほう (「s///g」の中の右側) を見ると、次のようになっています。

  • 「『<h1>』、ひとつめのグループのマッチ内容、ふたつめのグループのマッチ内容、『</h1>』」。
    -- 置換結果には「英数字が1文字」にあたるものがありません。

というわけで、わかりやすくまとめると、このs文は、次のような意味になるでしょう。
*「『<h1>』と『</h1>』の間に英数字があれば、そのうち一文字はとりあえず削除する」。

さて、maisumakunさんがおっしゃっているように、上の一行だけ実行しても、「<h1>」と「</h1>」の間のすべての英数字を削除することはできません。ですが繰り返しを使うことですべてを削除することができます。

:loop s/<h1>\(.*\)[a-za-z0-90-9]\(.*\)<\/h1>/<h1>\1\2<\/h1>/g tloop

これは複数行にわたるsedのプログラムですので、コマンドラインで実行するのには不向きです (できないわけではないですが)。上のプログラムをファイルに保存して実行したほうがいいでしょう。

また、新しく出てきた「:」と「t」の意味は、sedのマニュアルで調べて下さい。


seelさんのやりたいことを実現するには、まだいろいろとクリアしなければならない問題があるはずです。

たとえばここで出てきた例では、<h1>タグにしか対応していませんが、sedではもっと複雑なこともできます。

プログラムを書き換えたり、付け加えたりして、いろいろ試してみて下さい。また、sedのマニュアルを調べて、自分のやりたいことに合うようなやりかたがないか、探してみて下さい。

投稿2016/09/28 08:14

ikedas

総合スコア4333

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seel

2016/09/28 08:38

すみません、うまく理解できておりません。 なにげに素人考えで必要な処理を思いついて文章で質問した次第です。 一言で言うとsedで html内にある指定タグ範囲内で正規表現指定文字列部分を削除する。 これだけです。 正直思った以上に奥が深くて驚いています。  
seel

2016/09/28 10:16 編集

すみません、ちょっと試してきます。
seel

2016/09/28 10:17 編集

訂正をさせていただいましたが質問そのものを訂正したほうがいいでしょうか。
guest

0

ベストアンサー

1つ確認しておきたいことがありますが、<h1>内で英数字は「ひとかたまりになっています」でしょうか。

ひとかたまりの場合は、s/\(<h1>[^[:alnum:]]*\)[[:alnum:]]\+\([^[:alnum:]]*<\/h1>\)/\1\2/gのようにすればうまくいきます(なお、ロケールがUnicode対応になっている必要があります)。

ばらばらになっている場合、sedの機能では<h1></h1>内の複数箇所にヒットさせる、というのが難しいので、別な手段を考えたほうがいいと思います。

投稿2016/09/28 07:22

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seel

2016/09/28 08:34

ありがとうございます。 <h1></h1>内に複数にランダムに存在します。 別の方法もあるのですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問