行末から 2 番目のポイントを置き換えるにはどうすればよいですか?
11.22.mail.su => 11.22@mail.su
22.mails.de => 22@mails.de
等
sed
またはの例に興味がありawk
ます。
限りsed
、これを試してください:
sed -e 's/\.\([^.]*\.[^.]*\)$/@\1/'
そう:
# echo "11.22.mail.su" | sed -e 's/\.\([^\.]*\.[^\.]*\)$/@\1/g'
11.22@mail.su
# echo "22.mails.de" | sed -e 's/\.\([^\.]*\.[^\.]*\)$/@\1/g'
22@mails.de
あなたが何をしているのかを確認するために少し時間がかかりました。念のため、これは有効なメールアドレスです。
bob@mail.server.com
そしてこれもそうです:
bob.smith@mail.server.com
行末から2番目のピリオドを置き換えるとおっしゃいました。つまり、正規表現は行の終わりに固定する必要があります。$
正規表現の最後にあるAはまさにそれを行います。
あなたの例を見てみましょう:
11.22.mail.su
一致させたい.mail.su
。最後の文字である。から始めましょう$
。を実行することにより、文字の任意の組み合わせを表すことができ.*
ます。これは、ゼロから行の長さまでの任意の文字列を表します。ピリオドは任意の文字を*
表し、前の0個以上を表します。
ピリオドは特殊な正規表現文字であるため、ピリオドになるには、その前に円記号を付ける必要があります\.
。ここまでは順調ですね。
これは機能するはずです:
\..*\..*$
そして、一致させたいものを括弧で囲みます。
(\.)(.*)(\.)(.*)$
三!最初の(。)は、最後から2番目の期間をキャプチャします。次(.*)
は0個以上の文字をキャプチャし、3番目(.*)
は行の残りをキャプチャしてキャプチャ$
し、最後にアンカーします。
正規表現が貪欲であるため、実際には機能しないことを除いて。たとえば、これを正規表現として使用した場合:
.*###
そして私の文字列は次のようになります:
first###second###third###fourth
その正規表現はキャプチャしませんfirst###
。たまたまである可能性のある最長の文字列をキャプチャしますfirst###second###third###
。
これを回避する方法は、一致させたい文字を除外することです。この場合、に一致させたくありません#
。したがって、これを行うことができます。
[^#]*###
そして、それはにのみ一致しfirst###
ます。は、を除くすべての[^#]
文字を言います。は、0個以上の非#文字を意味します。したがって、上記の式のinを、ピリオド以外の任意の文字を意味するに置き換えます。#
*
.*
[^.]
前:
(\.)(.*)(\.)(.*)$
後:
(\.)([^.]*)(\.)([^.]*)$
2番目と4番目のグループの違いがわかりますか?
もう1つの小さな問題:sed
私が使用しているでは、括弧の前に円記号を付ける必要があります。そうしないと、実際には文字(
と)
文字列になります。これは、魔法にするために前にバックスラッシュを置く必要がある唯一のキャラクターです。他のすべての魔法の正規表現文字は、その前にバックスラッシュを置くまで魔法です。これは、これの代わりに次のことを意味します。
(\.)([^.]*)(\.)([^.]*)$
これを行う必要があります:
\(\.\)\([^.]*\)\(\.\)\([^.]*\)$
上記と同じですが、開き括弧と閉じ括弧の前に円記号が付いています。
これで、文字列の終わりに一致するものができました。置換を行いましょう。まず、簡単なテスト:
$ echo "11.22.mail.su" | sed 's/\(\.\)\([^.]*\)\(\.\)\([^.]*\)$/FOO/'
11.12FOO
うん、それは終わりに一致します。次に、グループ番号の前に円記号を付けることで、グループ化を参照できます。
$ echo "11.22.mail.su" | sed 's/\(\.\)\([^.]*\)\(\.\)\([^.]*\)$/@\2\3\4/'
11.22@mail.su
完全。最初のグループは私の最初の期間であることに注意してください。これを。に置き換え@
ます。次に、2番目、3番目、4番目のグループを維持したいと思います。したがって、私の置換文字列は@\2\3\4
です。
ちなみに、4つのグループは必要ありません。単純にピリオドに一致させてから、残りの行を1つのグループとして配置することができます。
echo "11.22.mail.su" | sed 's/\.\([^.]*\.[^.]*\)$/@\1/'
うん、正規表現はとてもシンプルで読みやすいです!私の友人は、正規表現をセーラーカッシングと呼んでいます。これは、古い漫画では、誰かが下品なものをたくさん配置するときに、正規表現の記号である可能性があるものを使用するためです。*
Perlの優れた機能の1つは、正規表現を複数行に分割できるため、何が起こっているのかをコメントできることです。
#! /usr/bin/env perl
$string = "11.22.mail.su";
$string =~ s/ #Start of my substitution
\. #A period
( #Start capturing a string
[^.]* #Everything up to the next period.
\. #The next period
[^.]*)$ #And capture it to the end of the line
/@\1/x; #Replace with a "@" and the rest of the string
print "String = '$string'\n";
$ test.pl
String = '11.22@mail.su'
Perlのもう1つの優れた点は、括弧の前に円記号を付けない限り、括弧には特別な意味があることです。(の反対sed
)。
私が手元で言及したことの1つですが、実際には焦点を当てていませんでした。これは、 0個以上の非期間に[^.]*
一致します。これは、正規表現の問題である可能性があります。問題を回避し、少なくとも1つの一致を強制するには、正規表現を2倍にする必要があります。たとえば、は一致し、単純にも一致します。[^#]*#FOO
THIS IS A #FOO
#FOO
これを行う[^#][^#]*#FOO
と、正規表現を2倍にすると、の前に少なくとも1つの非#
文字があることを保証でき#
ます。その正規表現は一致THIS IS A #FOO
しますが、単純なものだけではありません#FOO
。
だから、私たちはから行かなければならないかもしれません:
$ sed 's/\(\.\)\([^.]*\)\(\.\)\([^.]*\)$/FOO/'
に
$ sed 's/\(\.\)\([^.][^.]*\)\(\.\)\([^.][^.]*\)$/FOO/'
これは純粋なbashソリューションです(私はそれを使用することをお勧めしません。必要に応じて個々のステップを組み合わせることができます):
# An extended pattern to match a single field. letters, numbers, and a hyphen
# Add characters if necessary
shopt -s extglob
field='+([[:alnum:]-])'
for foo in 11.22.mail.su 22.mails.de; do
# The first part: drop the last two fields and the dots that precede them
first="${foo%.$field.$field}"
# The first part, followed by the @, followed by the full string minus the first
# part and its following dot.
modified="$first@${foo/#$first.}"
done
bash の正規表現サポートを使用する方が少し良いでしょう。
for foo in 11.22.mail.su 22.mails.de; do
[[ $foo =~ (.*)\.([^.]+\.[^.]+) ]]
# Three ways to join the two halves with @
one_way="$BASH_REMATCH[1]@${BASH_REMATCH[2]}
printf -v second_way "%s@%s" ${BASH_REMATCH[@]:1:2}
SAVE_IFS="$IFS"
IFS="@"
third_way="@{BASH_REMATCH[*]:1:2}"
IFS="$SAVE_IFS"
done