3

現在、文字列から特殊文字を取り除くため[^a-zA-Z0-9]に Java の関数を使用しています。replaceAllハイフンと数字が混在する場合は、ハイフンを許可する必要があることに気付きました。

ハイフンが一致しない例:

  • 1-2-3
  • -1-23-4562
  • --1---2--3---4-
  • --9--a--7
  • 425-12-3456

ハイフン一致する例:

  • --a--b--c
  • ウォルマート

この SO の質問を参照として使用して、後者の基準を満たす正規表現を策定したと思いますが、それを元の正規表現と組み合わせる方法はわかりません[^a-zA-Z0-9]

インデックス作成時に Lucene の標準トークナイザーが機能する方法のため、Lucene 検索文字列に対してこれを実行したいと考えています。

トークンに数字が含まれていない限り、単語をハイフンで分割します。数字が含まれている場合、トークン全体が製品番号として解釈され、分割されません。

4

4 に答える 4

2

単一の正規表現でこれを行うことはできません。(うーん...おそらくPerlで。)

編集:さて、可変長の否定的な後読みでそれを行うことができます.Javaは(ほぼ一意に!)できるようです;Cyborgx37の答えを参照してください。とにかく、単一の正規表現でこれを行うべきではありません.:))

できることは、文字列を単語に分割し、各単語を個別に処理することです。私のJavaはかなりひどいので、うまくいけば賢明なPythonがあります:

# Precompile some regex
looks_like_product_number = re.compile(r'\A[-0-9]+\Z')
not_wordlike = re.compile(r'[^a-zA-Z0-9]')
not_wordlike_or_hyphen = re.compile(r'[^-a-zA-Z0-9]')

# Split on anything that's not a letter, number, or hyphen -- BUT dots
# must be followed by whitespace
words = re.split(r'(?:[^-.a-zA-Z0-9]|[.]\s)+', string)

stripped_words = []
for word in words:
    if '-' in word and not looks_like_product_number.match(word):
        stripped_word = not_wordlike.sub('', word)
    else:
        # Product number; allow dashes
        stripped_word = not_wordlike_or_hyphen.sub('', word)

    stripped_words.append(stripped_word)

pass_to_lucene(' '.join(stripped_words))

これを で実行すると'wal-mart 1-2-3'、 が返され'walmart 1-2-3'ます。

しかし正直なところ、上記のコードは Lucene トークナイザーが既に行っていることのほとんどを再現しています。StandardTokenizer自分のプロジェクトにコピーして、やりたいように変更するだけのほうがいいと思います。

于 2013-01-18T21:13:45.393 に答える
1

Java ではルックアラウンドでの無限再帰が許可されていないため、この質問は扱いにくいものです。これは基本的に必要なものです。ご覧のとおり、100 文字の制限で作成しましたが、単語が長くなると予想される場合は、これを増やすことができます.

これはうまくいくはずです:

(?<![0-9]\S{0,100})[^a-zA-Z](?!\S{0,100}[0-9])|(?<=[0-9]\S{0,100})[^a-zA-Z0-9-](?=\S{0,100}[0-9])

この式を使用した単純な replaceAll() だけで処理できます。

たとえば、次の入力を検討してください。

--9-+-a--7 wal-mart

上記の式では、問題のある文字が長さ 0 の文字列に置き換えられ、次の出力が表示されます。

--9--a--7 walmart

ここで試すことができます: http://fiddle.re/ynyu

この表現は、空白 (スペース、タブ、改行など) で区切られた単語に依存することに注意してください。コンマやセミコロンなどの他の文字を使用すると、式は 2 つの単語を 1 つと見なします。たとえば、'---9-a-0-,wal-mart' は 1 つの単語として扱われます。

EDIT前回の編集の最後の段落が間違っていました。他の文字を区切り文字として含めたい場合は、最初のパスでそれらを空白に置き換えることをお勧めします (たとえば、',' を ' ' に置き換えます)。

私は主に .NET プログラマーですが、それ以外の場合は、このパターンを使用するための完全な Java コードを提供します。

于 2013-01-18T21:17:19.057 に答える
1

最初の回答を編集する代わりに 2 番目の回答を投稿することをお許しください。ただし、問題がダッシュがすぐに文字で囲まれている場合にダッシュを削除することなのか、それともダッシュを削除する文字列でのみダッシュを削除することが意図されているのかは完全にはわかりません。数字を一切含まない。この解決策は後者の場合です。私の他の解決策は、前者の場合です。

このパターン

String newValue = myString.replaceAll("[^\\sA-Za-z0-9\\-]|((?<!\\S*\\d)-(?!\\S*\\d))", "");

するべきです。で結合された 2 つの主要な部分がありますor。最初の部分は、アルファベット以外、数値、ダッシュ以外のすべての文字に一致します。これは、これらの文字を何があっても取り除きたいためです。の後半はor、トークン内でその前にも後ろにも数字がない (つまり、トークンがすべて非空白で構成されている場合、トークン内に数字がまったくない) 任意のダッシュに一致します。\S、文字)。これは、否定的な後読みと先読みによって実現されます。Java がこれらの先読み/後読みで可変幅をサポートしているという事実を利用していますもちろん、置換は単なる空の文字列です。

Java で正規表現を使用するための構文は面倒ですが (Pattern.compile などを使用する必要がある場合)、少なくともエンジンはいくつかの優れた機能をサポートしていることは認めざるを得ません。Eevee によると、.NET ほど良くはないかもしれませんが。

ただし、これは通常、単一の正規表現で実行したいことではないという点で、他の人に同意します。正確な状況はわかりませんが、製品番号のように見えるかどうかを検出し、正しいパターンを適用する単純な分岐は、はるかに読みやすくなります。

于 2013-01-19T04:13:52.503 に答える
1

これを試しましたか:

[^a-zA-Z0-9-]

于 2013-01-18T16:46:30.040 に答える