2016-09-30 9 views
0

I持って次の文字列:最後の単語を除く文字列のすべての単語をどのように一致させるのですか?

Chicago CPA 
New York CPA 
West Virginia Accountant 

がどのように私はいつもちょうど最後の単語の前に他のすべての単語を維持し、文字列の最後の単語(と前の空白)を切り落とすのですか?

したがって、上記のデータ・セットの正しいバージョンは次のようになります。

Chicago 
New York 
West Virginia 

また、それはRubularに一致するグループをテストすることが可能であるか、私は正規表現をテストするために使用できる別のオンライン正規表現エディタ/テスターがあります一致するグループと?

編集1

回答の多くは、理論的には素晴らしいです。私はそれらを読んで、私はそれらを理解し、私はバニラの文字列でそれらをテストし、彼らは動作するようです。しかし、私が自分のデータで試してみると、それはしません。私はしばらく悩まされていましたが、なぜ私はその理由を理解しました。

これは私が働いているHTMLです:

だから、このテキストは、私が上で、この文字列操作を行うにしようとしています:だからここ

Chicago&nbsp;<strong>Cpa</strong> 

することは、私がしようとすると何が起こるかでありますそれぞれ以下の答え。ダルシャンさん@


:ルーカス自身@

[56] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text 
=> "Chicago Cpa" 
[57] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.class 
=> String 
[58] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.match(/(.*) \w+\z/)[1] 
NoMethodError: undefined method `[]' for nil:NilClass 
from (pry):57:in `<class:PageCrawler>' 
[59] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text[/.*(?=\s\w+\z)/] 
=> nil 

:エリック自身@

[60] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text 
=> "Chicago Cpa" 
[61] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.class 
=> String 
[62] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.split()[0...-1].join(' ') 
=> "" 

[65] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text 
=> "Chicago Cpa" 
[66] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.class 
=> String 
[67] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.split().reverse.drop(1).reverse.join(" ") 
=> "" 
Santosh自身@

[68] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text 
=> "Chicago Cpa" 
[69] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.class 
=> String 
[70] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.sub(/\W+\w+\W*$/, '') 
=> "Chicago" 

:カシミール自身(この1つは実際には、これまでの最高である)@


[71] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text 
=> "Chicago Cpa" 
[72] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text.class 
=> String 
[73] pry(YPCrawler::PageCrawler)> @document.css('header h1.search-term').first.text[/(.*)\s/,1] 
=> nil 

やっていないために私の謝罪これより早いですが、私はこれが問題であるとは予想していませんでした。これを達成する

答えて

4

私はこのかどうか、私は正規表現で、特に良好ではない、と私は私の頭の上からわからないんだけど(でも私はベンチマークに傾い感じるかについてのハードだと思います)と言って序文ます@ LucasPの正規表現以外のアプローチよりも効率的である傾向があります。しかし、これは私のために頭に浮かぶ明らかアプローチがある:一つ以上の単語文字がスペースで始まる文字列の末尾にマッチし、あなたがつかむグループに、その前にすべてのものを置く

s.match(/(.*) \w+\z/)[1] 

data = ['Chicago CPA', 
     'New York CPA', 
     'West Virginia Accountant'] 

data.map{|s| s.match(/(.*) \w+\z/)[1]} 
# => ["Chicago", "New York", "West Virginia"] 

編集:このアプローチでバリアント、@CarySwovelandによって提案されたが、むしろに私たちが望むの部分を入れて、私の最初のアプローチよりも、私たちは破棄したい部分を無視するように先読み表現を使用することです私たちがアクセスするキャプチャグループです。ここではそのアプローチのバージョンがあります:

data.map{|s| s[/.*(?=\s\w+\z)/]} 
# => ["Chicago", "New York", "West Virginia"] 

編集2:が追加した情報と、それはあなたが直面した問題は、あなたも\sと一致していない非破壊スペースを、持っていることであることが明らかです(\sは、ASCII空白にのみ一致し、[ \t\r\n\f]に相当)。したがって、POSIXブラケット式[[:space:]]を使用するか、または改行しない空白文字には\u00A0を明示的に一致させるかのいずれかを使用します。すべてが改行されないスペースであると仮定します。続き

'West Virginia Accountant'.sub(/\W+\w+\W*$/, '') 
+0

に変更します。あなたはどこに行くのか見ていますが、この正規表現はRubular.comごとに 'Chicago CPA'と一致しません。 – marcamillion

+2

@marcamillionにもマッチします。私のマシンとrubular.comの両方で私にとってはうまくいきます。あなたのデータセットを16進エディタにダンプし、空白で何が起こっているのかを見てみましょう。 –

+1

@marcamillion http://rubular.com/r/b9X60eAwNc –

2

一つの方法は以下の通りである。

myStringはあなたが上でこの操作を実行する各文字列です
myString.split()[0...-1].join(' ') 

  1. まず、文字列から各単語を含むリストに分割します。

  2. 次に、最後の要素を除くすべての要素を含むサブリストを選択します。

  3. 最後に、リストから文字列に戻ります。

+0

だから私は最初は似たようなことを試みましたが、これらの文字列を分割しようとすると、奇妙なことが起こっています。 '>" Chicago Cpa ".split => [" Chicago Cpa "]'。それは各単語のための新しい要素を作成しません...私は奇妙な発見。これを引き起こす原因は何ですか? – marcamillion

+1

@marcamillionコピー&ペーストすると、期待通りに[["Chicago"、 "Cpa"] 'が得られます。あなたの文字列にうねった空白がある可能性はありますか? –

+0

それは非常に奇妙です。なぜ私が正しく分裂していないのか分かりません。私はうねった空白を見ていない。 – marcamillion

0
"New York Accountant".split().reverse.drop(1).reverse.join(" ") 
+2

'split [0 ..- 2]'は 'split()。reverse.drop(1).reverse'よりも直接的ではありませんか? –

+0

はい、これは別のオプションです... – Eric

+0

あなたの提案が私の実際のデータに作用していない理由を理解するのに苦労しましたが、バニラストリングを試してみるとうまくいきます。私は、私のデータが実際にどのように見えるかについて、より詳細な質問を更新しました。 – marcamillion

1

は、あなたが交換を使用することができます:あなたは時々そこに他の空白があるかもしれないので、私は、かつてのを好みます。

str = ['Chicago CPA', 'New York CPA', 'West Virginia Accountant'] 

str.map{|s| s[0...s.rindex(' ')]} 

出力:正規表現を使用して["Chicago", "New York", "West Virginia"]

str2 = "West Virginia Accountant" 
p str2[/(.*)\s/,1] 

出力:"West Virginia"

+0

このアプローチを使用する際の短所は何ですか?これが偽陽性を投げるケースは何ですか? – marcamillion

+0

@marcamillion:それはあなたが "単語"と呼ぶかどうかに依存します。たとえば、このパターンはアクセント記号のついた単語で失敗します(しかし、これは少々の変更で簡単に解決できます)。または "Scarlett O 'Hara' =>「Scarlett O」、頭字語「米国生まれ」=>「米国生まれ」、パターンを「/ \ p {Z} + \ P {Z} + \ p」に変更することができます{Z} * $/'(' \ p {Z} 'はすべてのUnicode区切り文字と一致します)。 –

0

試してください:あなたは複数の単語を持っていると仮定すると

data.map{|s| s[/.*(?=[[:space:]]\w+\z)/]} 
+0

あなたの提案が私の実際のデータではうまくいかない理由を理解するのに苦労しましたが、バニラストリングを試してみるとうまくいきます。私は、私のデータが実際にどのように見えるかについて、より詳細な質問を更新しました。 – marcamillion

+0

@marcamillionには、実際の文字列に ' 'が含まれています。私の正規表現はそれを検出できません。だからあなたは正規表現 '/ \ W + \ w + \ W * $ /'を使うことができます。あなたの実際の文字列を過ぎることができますか? –

0

あなたが最後の言葉が、すべてのものをキャプチャするために正規表現/^(.*)\s+\w+\s*$/を使用することができます。

例:

str = <<~EOF 
     Chicago CPA 
     New York CPA 
     West Virginia Accountant 
EOF 

str.each_line do |line| 
     puts line.match(/^(.*)\s+\w+\s*$/).captures.first 
end 

出力:

Chicago 
New York 
West Virginia 
関連する問題