正規表現について教えて下さい。

投稿者: Anonymous

Twitterのリプライなどの@から始まるユーザ名や画像,やウェブページなどのhttp(s)で始まる文字列を削除したいと考えています。

いろいろためして見ましたがなかなかすべてにマッチするものを見つけられませんでした。

target := []string{"@abcde ああああ https://t.co/aaa あああ", "いいいい @abcde ssadsa", "https://t.co/bbb うううう @abcde", "[email protected]"}

このような文字列から上記のような文字列を削除したいと考えています。最後の[email protected]は削除しないようにしたいです。

このような場合どのような正規表現を作成すればいいのでしょうか。

解決

問題点を見つけたのですが、正規表現だけではどうにも対応ができませんでしたので、面倒くさい事をしています。

re, _ := regexp.Compile(`(^|s)(@|https?://)S+`)
re2, _ := regexp.Compile(`^s*|s*$`)
for _, v := range target {
  // "いいいい @abcde ssadsa" => "いいいい ssadsa"
  fmt.Printf("   Replace: %#vn",
    re2.ReplaceAllString(re.ReplaceAllString(v, ""), ""))

  // "いいいい @abcde ssadsa" => "いいいいssadsa"
  splitted := re.Split(v, -1)
  for i, v := range splitted {
    splitted[i] = re2.ReplaceAllString(v, "")
  }
  fmt.Printf("Split&Join: %#vn", strings.Join(splitted, ""))
}

実は、以下の正規表現を使用して、

(^|s)(@.+?|https?.*?)($|s)

以下の文字列に対して ReplaceAllString() を実行すると、

"@abcde https://t.co/aaa あああ"
=> "https://t.co/aaa あああ"

となってしまいます。本来は、

"あああ"

となるはずです。理由は、、お分かりかと思います。

追記

Perl で試してみると、

$str = '@abcde https://t.co/aaa あああ';
$str =~ s/(^|s)(@.+?|https?.*?)($|s)//g;
print $str . "n";
=> https://t.co/aaa あああ

同じ結果になります。そこで、否定的先読み(negative lookahead)を用いると、期待する結果が得られます。

$str = '@abcde https://t.co/aaa あああ';
$str =~ s/((^|s)(@|https?://)S+)|(s(?!(@|https?://)))//g;
print $str . "n";
=> あああ

ですが、golang の regexp package では否定的先読みを使うことができません(NOT SUPPORTED)。

そこで、PCRE package を使います。まずは go get で package をインストールします。

$ go get github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre

以下はテストプログラムとその実行結果です。

test_regexp.go

package main

import (
  "fmt"

  "github.com/glenn-brown/golang-pkg-pcre/src/pkg/pcre"
)

func main() {
  target := []string{
    "@abcde https://t.co/aaa あああ",
    "いいいい @abcde ssadsa",
    "https://t.co/bbb うううう @abcde",
    "[email protected]",
    "ええ @bar.baz @foo xyz",
    "@bar.baz https://t.co/ccc おお @xyz [email protected]",
  }

  re, _ := pcre.Compile(`((^|s)(@|https?://)S+)|(s(?!(@|https?://)))`, 0)
  for _, v := range target {
    fmt.Printf("  Source: %#vn", v)
    fmt.Printf("Replaced: %#vn", string(re.ReplaceAll([]byte(v), []byte(""), 0)))
  }
}

実行結果

$ go run test_regexp.go
  Source: "@abcde https://t.co/aaa あああ"
Replaced: "あああ"
  Source: "いいいい @abcde ssadsa"
Replaced: "いいいいssadsa"
  Source: "https://t.co/bbb うううう @abcde"
Replaced: "うううう"
  Source: "[email protected]"
Replaced: "[email protected]"
  Source: "ええ @bar.baz @foo xyz"
Replaced: "ええxyz"
  Source: "@bar.baz https://t.co/ccc おお @xyz [email protected]"
Replaced: "おお[email protected]"
回答者: user9156

Leave a Reply

Your email address will not be published. Required fields are marked *