2016-09-30 4 views
0

Ich habe folgende Strings:Wie passe ich jedes Wort in einer Zeichenfolge außer dem letzten Wort an?

Chicago CPA 
New York CPA 
West Virginia Accountant 

Wie kann ich abhacken immer nur das letzte Wort (und das vorhergehende Leerzeichen) in der Zeichenfolge, alle anderen Worten, bevor das letzte Wort zu bewahren?

Also die richtigen Versionen der oben genannten Datensatzes wäre:

Chicago 
New York 
West Virginia 

Auch ist es möglich, Gruppen auf Rubular zu testen passende oder gibt es einen anderen Online-regex-Editor/Tester, die ich verwenden kann, reguläre Ausdrücke zu testen mit passenden Gruppen?

Edit 1

Viele der Antworten in der Theorie groß sind. Ich lese sie, ich verstehe sie und ich teste sie an einer Vanilleschnur und sie scheinen zu funktionieren. Aber wenn ich es auf meine Daten versuche, tut es das nicht. Ich war eine Weile ratlos, und mir wurde gerade klar warum.

Dies ist die HTML an dem ich arbeite:

dies also der Text, ich bin versucht, auf diese String-Manipulation zu tun:

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

hier So ist das, was passiert, wenn ich versuche, jede der Antworten unten.


@ Darshan suchen:

[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 

@ Lucas eigenen:

[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(' ') 
=> "" 

@ Eric eigenen:

[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(" ") 
=> "" 

@ Casimir eigenen (dies ist bei weitem das beste, tatsächlich):

[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" 

@ Santosh eigenen:

[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 

Ich entschuldige mich nicht zu tun dies früher, aber ich habe nicht erwartet, dass dies ein Problem ist.

Antwort

4

ich sagen, ich bin nicht besonders gut mit regulären Ausdrücken Vorwort werde, und ich bin aus der Spitze von meinem Kopf nicht sicher (noch habe ich zu Benchmark geneigt fühlen oder denken intensiv darüber), ob diese würde tendenziell mehr oder weniger effizient sein als @ LucasPs Nicht-Regex-Ansatz. Aber das ist die offensichtliche Ansatz, der für mich in den Sinn kommt:

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

, dass am Ende der Zeichenfolge entspricht einem oder mehreren Wort durch ein Leerzeichen voran Zeichen und setzt alles vor, dass in einer Gruppe, die Sie dann greifen .

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

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

Edit: Eine Variante dieses Ansatzes durch @CarySwoveland vorgeschlagen, ist ein Look-Ahead-Ausdruck verwenden, um den Teil, den wir, anstatt meine erste Annäherung des Setzens der Teil, den wir wollen in eine verwerfen wollen ignorieren Fanggruppe, auf die wir dann zugreifen. Hier ist eine Version dieses Ansatzes:

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

Edit 2: Mit Ihren zusätzlichen Informationen ist es nun klar, dass das Problem, das Sie konfrontiert wurden, ist, dass Sie nicht brechen Räume haben, die auch bei \s nicht überein (\s entspricht nur ASCII-Leerzeichen, entspricht [ \t\r\n\f]). Verwenden Sie also den POSIX-Klammerausdruck [[:space:]] oder passen Sie explizit \u00A0 für das nicht brechende Leerzeichen an, vorausgesetzt, dass alle nicht brechenden Leerzeichen sind. Ich ziehe den ehemaligen, da man dort andere Leerzeichen manchmal haben könnte:

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

Ich sehe, wohin du gehst, aber diese Regexp scheint nicht mit 'Chicago CPA' pro Rubular.com übereinzustimmen. Es passt nur – marcamillion

+2

@marcamillion Wieder funktioniert es für mich sowohl auf meiner Maschine als auch bei rugular.com. Ich würde Ihre Datenmenge in einen Hex-Editor ablegen und sehen, was mit Ihrem Leerzeichen passiert. –

+1

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

2

Eine Möglichkeit, dies zu erreichen, ist die folgende:

myString.split()[0...-1].join(' ') 

Wo myString ist jede Zeichenfolge, die Sie auf diese Operation ausgeführt werden soll.

  1. Zuerst teilen Sie die Zeichenfolge in eine Liste mit jedem Wort.

  2. Wählen Sie dann die Unterliste, die alle Elemente außer dem letzten enthält.

  3. Schließlich gehen Sie zurück von der Liste zu einer Zeichenfolge.

+0

Also habe ich anfangs etwas Ähnliches versucht, aber das Seltsamste passiert, wenn ich versuche, diese Saiten zu trennen. '>" Chicago Cpa ".split => [" Chicago Cpa "]'. Es schafft kein neues Element für jedes Wort ... was ich seltsam finde. Was könnte das verursachen? – marcamillion

+1

@marcamillion Wenn ich das kopiere und einfüge, bekomme ich '[" Chicago "," Cpa "]' wie erwartet. Ist es möglich, dass du in deinen Strings etwas wackligen Whitespace hast? –

+0

Das ist sehr bizarr. Ich bin mir nicht sicher, warum ich mich nicht richtig aufspalte. Ich sehe keine wackeligen Whitespaces. – marcamillion

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

Ist 'split [0 ..- 2]' nicht direkter als 'split(). Reverse.drop (1) .reverse'? –

+0

Ja, aber das ist eine andere Option ... – Eric

+0

Ich hatte Schwierigkeiten herauszufinden, warum Ihr Vorschlag nicht an meinen tatsächlichen Daten arbeitete, aber wenn ich es mit einer Vanilleschnur versuche, funktioniert es. Ich habe die Frage mit mehr Details darüber, wie meine Daten tatsächlich aussehen, aktualisiert. – marcamillion

1

Vorausgesetzt, dass Sie mehr als ein Wort haben, können Sie einen Ersatz verwenden.

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

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

Ausgang: ["Chicago", "New York", "West Virginia"]

Regexp verwenden.

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

Ausgang: "West Virginia"

+0

Was sind die Nachteile dieses Ansatzes? Was sind die Fälle, dass dies ein falsches positives werfen wird? – marcamillion

+0

@marcamillion: Es hängt davon ab, was Sie "ein Wort" nennen, zum Beispiel wird dieses Muster mit einem Wort mit akzentuierten Buchstaben fehlschlagen (aber dies kann leicht mit ein paar Änderungen gelöst werden), oder mit einem Namen, der Zitate wie "Scarlett O "Hara" => "Scarlett O" oder mit Akronymen "geboren in den USA" => "in den USA geboren", aber du kannst das Muster in '/ \ p {Z} + \ P {Z} + \ p ändern {Z} * $/'(wobei' \ p {Z} 'mit allen Unicode-Trennzeichen übereinstimmt). –

0

Versuchen Folgende:

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

Ich hatte Probleme herauszufinden, warum dein Vorschlag nicht an meinen tatsächlichen Daten arbeitete, aber wenn ich es mit einer Vanilleschnur versuche, funktioniert es. Ich habe die Frage mit mehr Details darüber, wie meine Daten tatsächlich aussehen, aktualisiert. – marcamillion

+0

@marcamillion in Ihrer tatsächlichen Zeichenfolge es ' ' enthalten. also kann meine Regex das nicht erkennen. Sie können also Regex '/ \ W + \ w + \ W * $ /' verwenden. Kannst du deine eigentliche Zeichenfolge überspringen? –

0

Sie die Regex verwenden können /^(.*)\s+\w+\s*$/ alles, aber das letzte Wort zu erfassen:

Beispiel:

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 

Ausgang:

Chicago 
New York 
West Virginia 
Verwandte Themen