2016-02-05 84 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。

如果我有时间,我会回来,并在稍后解压。