正規表現でn個の単語をどのように一致させるのですか?

私の頭を掻き、広範囲にグーグルグーグルをした後、私はこの権利を得ることができない。

私はこのサンプル文字列を持っています:

test = "真の売上高は50%から60%   前年度に報告されたもの。主な理由は   間違いなく偽の売上高は、   25%と35%低下します」。

私は本当の売上高が高いか低いかを判断しようとしています。 R と 'stringr'ライブラリを使用して、私は次のように試しています:

test = "true sales are expected to be between 50% and 60% higher than those reported for the previous corresponding year. the main reason is blah blah. the fake sales are expected to be in the region of between 25% and 35% lower."
positive.regex = "(sales).*?[0-9]{1,3}% higher"
negative.regex = "(sales).*?[0-9]{1,3}% lower"

次の結果が得られます。

str_extract(test、positive.regex)       [1]「売上高は50%から60%   str_extract(test、negative.regex)       [1] "売上高は50%から60%       前年度の報告値を上回っています。主な理由はまあまあです。偽の売上高は25%から35%の間の領域にあると予想されます」

私は、(売上)と '%higher' または '%lower' の間にマッチする単語の数を制限する方法を見つけようとしているので、マッチしない。つまり私は '。*?'を置き換える必要があることを知っています。文字ではなく単語全体にマッチし、これらの単語の数を3〜5のように制限すると、どうすればいいですか?

3
あなたはロアルドダールのファンではありませんか?
追加された 著者 Tim Pietzcker,
母、私は実際には:-)
追加された 著者 Jorgy Porgee,

4 答え

正規表現の。?部分に higher lower という単語が含まれないようにする必要があります。これを行う1つの方法は、否定的な先読みアサーションを使用することです。

positive.regex = "sales(?:(?!higher|lower).)*[0-9]{1,3}% higher"
negative.regex = "sales(?:(?!higher|lower).)*[0-9]{1,3}% lower"

説明:

(?:      # Match...
 (?!     #  (unless we're at the start of the word
  higher #   "higher"
 |       #   or
  lower  #   "lower"
 )       #  )
 .       # any character
)*       # Repeat any number of times.
2
追加された
perl = TRUE を追加する必要があります。
追加された 著者 Vincent Zoonekynd,
こんにちはティム、お返事ありがとうございます。上記のことは意味がありますが、先読みアサーションについての私の完全な無知にもかかわらず、私はそれを実行しようとするとエラーが発生します(無効なregexp):regexprのエラー( "sales(?:( ?! higher | lower)。 )* [0-9] {1,3}%lower "、...無効な正規表現 'sales(?:( ?! higher | lower))* [0-9] {1,3}%lower' 、理由 '無効なregexp'それを修正する方法についての任意の考えですか?
追加された 著者 Jorgy Porgee,
このVincentを強調してくれてありがとう。 perl regexesを有効にしようとしましたが(stringr vignetteによると、perl(パターン)を使用しています)、動作しません。ここでは失敗したビネットで与えられた例がありますが、それはあなたのために働くのですか? str_detect(strings、perl(pattern)) pattern < - "(?x)ab" /code> check_pattern(pattern、string)のエラー:関数 "perl"が見つかりませんでした
追加された 著者 Jorgy Porgee,
stringr(0.6)の最新バージョンにアップグレードすることでこれを修正しました。このソリューションは、私が最初に考えていたよりもうまく機能します(n個の単語にマッチする)。多くのおかげで、もう一度。
追加された 著者 Jorgy Porgee,

これは、 gsubfn パッケージを使用します。指定された正規表現の出現を見つけ、 max.width 以下の単語が一致するかどうかを確認します。

library(gsubfn)

max.words <- 11
num.words <- function(x) length(strsplit(x, "\\s+")[[1]])

strapply(test, "(sales.*?\\d+% (higher|lower))", function(x, y) 
    if (num.words(x) <= max.words) x)

必要に応じて、ifステートメントを展開して "higher" または "lower" に制限することができます。

strapply(test, "(sales.*?\\d+% (higher|lower))", function(x, y) 
    if (num.words(x) <= max.words && y == "higher") x)

この関数は、次のような式の表記法で記述することもできます(上記の最後の例の場合)。

strapply(test, "(sales.*?\\d+% (higher|lower))", 
    ... ~ if (num.words(..1) <= max.words && ..2 == "higher") ..1)
1
追加された
ありがとう、これは単語を数えるのに最適です。
追加された 著者 Jorgy Porgee,

両方に一致する正規表現を使用してみませんか?最後の単語が「上位」か「下位」かを確認できます。

r <- "sales.*?[0-9]{1,3}% (higher|lower)"
str_match_all(test,r)
0
追加された
ハイ・ヴィンセント、あなたの提案に感謝します。私は何百ものテキストを「真の」販売にのみ基づいて分類したいので、両方の正規表現はできません。さらに、ここでの「偽」という言葉は、実際には例を単純化するために使用されていますが、偽の販売はきちんと定義されていません。
追加された 著者 Jorgy Porgee,

単にこれを使用した場合:

true sales.+higher

...それはうまくいくだろうが、後に文が "偽の売り上げが高い"と言えば、マッチングが終わるかもしれないという事実のために。ですから、これを回避するには、次のようにします:

true sales.+higher.+fake

上記が一致すれば、実際の売上高は確かに高くなります。次のものが一致する場合:

本当の販売+低い+偽物

そして、本当の売上は低くなります。もちろん、少し原油です。改行を含めるには、ドットを[\ s \ S]に置き換えることもできます。お役に立てれば。

0
追加された
提案ありがとう。残念なことに、私はこれらの正規表現を実行している文字列の構造は非常に不規則なので、私は単にそれを解決する正規表現の末尾に '偽'をタックすることはできません( '偽'の代わりに私はこの特定の販売番号を「偽」として無視しなければならないという意味です)。私の考えは、単語の数を「売上高」と「高値」の間に制限することでしたが、それをどうやって行うのかは分かりません。
追加された 著者 Jorgy Porgee,