2016-02-05 41 views
0

我有兩個地址的數據側由端在多行字符串:如何從文本中提取列

Adresse de prise en charge :       Adresse d'arrivée : 


    rue des capucines          rue des tilleuls 


    92210  Saint Cloud        67000   Strasbourg 

    Tél.:             Tél.: 

我需要提取的左側和右側用正則表達式的地址,並分配他們變量。我需要匹配:

  • address1"rue des capucines 92210 Saint Cloud"
  • address2"rue des tilleuls 67000 Strasbourg"

我想用空格分開的,但我不能找到任何正則表達式來算的空間。我試過:

en\s*charge\s*:\s*((.|\n)*)\s* 

和類似的,但是這給了我兩個地址,而不是我在找什麼。任何幫助將深表謝意。

+3

請將1)作爲文本發佈在問題中的輸入,2)解釋您想要在該文本中匹配的內容。 –

+0

我添加了一張照片。但你是對的,我會編輯我的問題更加明顯。謝謝! –

+1

請1)將問題中的輸入作爲文本發佈,2)解釋您想要在該文本中匹配的內容。 – mudasobwa

回答

2

假設每行中的每個地址段的縮進量都比第一行中對應的"Adresse"的縮進量要多或更多,以下內容不僅可以提取兩個側向對齊的地址,而且還可以提取一般情況下的n個地址。

lines = string.split(/#{$/}+/) 
# => [ 
# => "Adresse de prise en charge :       Adresse d'arrivée :", 
# => " rue des capucines          rue des tilleuls", 
# => " 92210  Saint Cloud        67000   Strasbourg", 
# => " Tél.:             Tél.:" 
# => ] 

break_points = [] 
lines.first.scan(/\bAdresse\b/){break_points.push($~.begin(0))} 
ranges = break_points.push(0).each_cons(2).map{|s, e| s..(e - 1)} 
# => [0..53, 54..-1] 

address1, address2 = 
lines[1..-2] 
.map{|s| ranges.map{|r| s[r]}} 
.transpose 
.map{|a| a.join(" ").strip.squeeze(" ")} 
# => [ 
# => "rue des capucines 92210 Saint Cloud", 
# => "rue des tilleuls 67000 Strasbourg" 
# => ] 
+1

你可能想要修改'split($ /)'。 –

+0

剛試過你的答案,它的工作!非常感謝您的幫助! :) –

+0

你剛剛救了我的一天! –

3

我會做這樣的事情:

str = <<EOT 
Adresse de prise en charge :       Adresse d'arrivée : 


    rue des capucines          rue des tilleuls 


    92210  Saint Cloud        67000   Strasbourg 

    Tél.:             Tél.: 
EOT 

left_addr = [] 
right_addr = [] 

lines = str.squeeze("\n").gsub(':', '').lines.map(&:strip) # => ["Adresse de prise en charge       Adresse d'arrivée", "rue des capucines          rue des tilleuls", "92210  Saint Cloud        67000   Strasbourg", "Tél.             Tél."] 
center_line_pos = lines.max.length/2 # => 35 

lines.each do |l| 
    left_addr << l[0 .. (center_line_pos - 1)].strip 
    right_addr << l[center_line_pos .. -1].strip 
end 

此時left_addrright_addr樣子:

left_addr # => ["Adresse de prise en charge", "rue des capucines", "92210  Saint Cloud", "Tél."] 
right_addr # => ["Adresse d'arrivée", "rue des tilleuls", "67000   Strasbourg", "Tél."] 

而這裏所包含的內容:

puts left_addr 
puts '------' 
puts right_addr 

# >> Adresse de prise en charge 
# >> rue des capucines 
# >> 92210  Saint Cloud 
# >> Tél. 
# >> ------ 
# >> Adresse d'arrivée 
# >> rue des tilleuls 
# >> 67000   Strasbourg 
# >> Tél. 

如果你所需要的結果都在一行中沒有「電話:」:

puts left_addr[0..-2].join(' ').squeeze(' ') 
puts '------' 
puts right_addr[0..-2].join(' ').squeeze(' ') 

# >> Adresse de prise en charge rue des capucines 92210 Saint Cloud 
# >> ------ 
# >> Adresse d'arrivée rue des tilleuls 67000 Strasbourg 

這裏是正在發生的事情的細目:

str.squeeze("\n") # => " Adresse de prise en charge :       Adresse d'arrivée :\n rue des capucines          rue des tilleuls\n 92210  Saint Cloud        67000   Strasbourg\n Tél.:             Tél.:\n" 
    .gsub(':', '') # => " Adresse de prise en charge       Adresse d'arrivée \n rue des capucines          rue des tilleuls\n 92210  Saint Cloud        67000   Strasbourg\n Tél.             Tél.\n" 
    .lines   # => [" Adresse de prise en charge       Adresse d'arrivée \n", " rue des capucines          rue des tilleuls\n", " 92210  Saint Cloud        67000   Strasbourg\n", " Tél.             Tél.\n"] 
    .map(&:strip) # => ["Adresse de prise en charge       Adresse d'arrivée", "rue des capucines          rue des tilleuls", "92210  Saint Cloud        67000   Strasbourg", "Tél.             Tél."] 
+0

謝謝你的幫助! –

+0

沒有必要感謝我們,實際上這個網站不鼓勵它。 –

+0

如果照亮發件人或收件人的日子,偶爾的「謝謝」有什麼危害? –

2

假設

我都以爲,不需要第一行和最後一行,並且街道名稱至少用兩個空格分隔,而郵政編碼/城市字符串則相同。這允許「獎費」的街道名稱(和郵政編碼/城市對)在「Adresse d'arrivée:」之下結束。

代碼

def parse_text(text) 
    text.split(/\n+\s+/)[1..-2]. 
     map { |s| s.gsub(/\d+\K\s+/,' ').split(/\s{2,}/) }. 
     transpose. 
     map { |a| a.join(' ') } 
end 

實例

實施例1

text = <<BITTER_END 
Adresse de prise en charge :       Adresse d'arrivée : 


    rue des capucines          rue des tilleuls 


    92210  Saint Cloud        67000   Strasbourg 

    Tél.:             Tél.: 
BITTER_END 


parse_text(text) 
    #=> ["rue des capucines 9210 Saint Cloud", 
    # "rue des tileuls 670 Strasbourg"] 

實施例2

text = <<_ 
Adresse 1 :    Adresse 2 :     Adresse 3 : 


    rue nom le plus long du monde par un mile rue gargouilles rue des tilleuls 


    92210   Saint Cloud 31400 Nice    67000  Strasbourg 

    France      France      France 

    Tél.:      Tél.:      Tél.: 
_ 

parse_text(text) 
    #=> ["rue nom le plus long du monde par un mile 92210 Saint Cloud France", 
    # "rue gargouilles 31400 Nice France", 
    # "rue des tilleuls 67000 Strasbourg France"] 

說明

的問題給出text步驟:

分割成線,去除空白行和前導空格:

a1 = text.split(/\n+\s+/) 
    #=> ["Adresse de prise en charge :      Adresse d'arrivée :", 
    # "rue des capucines         rue des tilleuls", 
    # "92210  Saint Cloud        67000   Strasbourg", 
    # "Tél.:            Tél.:\n"] 

刪除第一行和最後一行:

a2 = a1[1..-2] 
    #=> ["rue des capucines         rue des tilleuls", 
    # "92210  Saint Cloud        67000   Strasbourg"] 

的郵政編碼和城市之間刪除多餘的空格,並在兩個或多個空格分割每行:經柱

r =/
    \d+ # match one or more digits 
    \K # forget everything matched so far 
    \s+ # match one of more spaces 
    /x # extended/free-spacing regex definition mode 

a3 = a2.map { |s| s.gsub(/\d+\K\s+/,' ').split(/\s{2,}/) } 
    #=> [["rue des capucines", "rue des tilleuls"], 
    # ["92210 Saint Cloud", "67000 Strasbourg"]] 

組:

a4 = a3.transpose 
    #=> [["rue des capucines", "92210 Saint Cloud"], 
    # ["rue des tilleuls", "67000 Strasbourg"]] 

加入字符串:

a4.map { |a| a.join(' ') } 
    #=> ["rue des capucines 92210 Saint Cloud", 
    # "rue des tilleuls 67000 Strasbourg"] 
+1

小心。只要使用'squeeze',就有可能將其應用於任何可能出現的連續字符。事實上,你因此得到了錯誤的答案。 – sawa

+0

謝謝,@sawa。我解決了這個問題並做了一些其他更改。我們的答案可能正在趨同。 –

0

假設「中心線位置」是已知的,這將起作用:

left_lines, right_lines = str.scan(/^(.{50})(.*)$/).transpose 

正則表達式在每行的開始處捕獲50個字符加上剩餘字符直到行結束。

scan返回嵌套陣列:(我使用佔位符,因爲實際的線是太長)

[ 
    ['1st left line', '1st right line'], 
    ['2nd left line', '2nd right line'], 
    ... 
] 

transpose其轉換爲:

[ 
    ['1st left line', '2nd left line', ...], # <- assigned to left_lines 
    ['1st right line', '2nd right line', ...] # <- assigned to right_lines 
] 

的線(不包括所述第一和最後一行)必須是join ed,並且空格必須被刪除:(見stripsqueeze

left_lines[1..-2].join(' ').strip.squeeze(' ') 
#=> "rue des capucines 92210 Saint Cloud" 

同爲right_lines

right_lines[1..-2].join(' ').strip.squeeze(' ') 
#=> "rue des tilleuls 67000 Strasbourg" 
+1

這假設有一個「中心線」。看起來好像有一個,但我們不知道如果第一個組中的街道名稱太長以至於它會在第二個列標籤下面結束(如果未截斷),會發生什麼情況。簡單地假設街道名稱至少有兩個空格分隔並且與郵政編碼/城市字符串相同可能會更好。如果你想保持中心線的方法,最好計算它(例如,'arr = text.lines; i = arr.max_by(&:size).max.times.find {| i | arr [i,2] ==''}'。 –

2
str = 
" Adresse de prise en charge :       Adresse d'arrivée : 


    rue des capucines          rue des tilleuls 


    92210  Saint Cloud        67000   Strasbourg 

    Tél.:             Tél.:" 

adr_prise, adr_arr = str.lines[3].strip.split(/ {2,}/) #split on 2+ spaces 
code_prise, cite_prise, code_arr, cite_arr = str.lines[6].strip.split(/ {2,}/) 
1

通過@steenslag's very pragmatic answer啓發,這裏是一個非常密集的一個班輪只是爲了好玩。

# Assume the input data is in the variable `text` 
left_addr, right_addr = text.lines.values_at(3, 6).map do |line| 
    line.scan(/(?:\d+ +)?\S+(?: \S+)*/) 
     .map {|part| part.squeeze(' ') } 
    end 
    .transpose 
    .map {|addr| addr.join(' ') } 

puts left_addr 
# => rue des capucines 92210 Saint Cloud 
puts right_addr 
# => rue des tilleuls 67000 Strasbourg 

像@ steenslag的答案,這是假定所需的數據始終是線3和6它還假定在6號線兩列將有一個郵編,城市和郵政編碼總是會啓動與一個數字。

因爲它是一個非常密集的單線程,因爲它做了很多假設,我不認爲這是最好的答案,我將它標記爲社區Wiki。

如果我有時間,我會回來,並在稍後解壓。