csv 将特定正则表达式捕获组的多行文本括在引号内

q8l4jmvw  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(83)

我的输入是来自不同来源的文本,唯一一致的是它们都包含一个代码,纬度和经度。这有时是有用的注解。
从这个输入中,目标是生成一个CSV格式,其标题行为:代码、名称、纬度、经度、注解、URL、注解
仅需要代码、纬度、经度和可能的注解
使用PCRE 2时,替换字符串为Code,,Latitude,Longitude,“Notes”,,

$1,,$2,$3,"$4",,

字符串
我的RE几乎在做我想做的事情

(?mi)^.*?((?:\bGC)[A-Z0-9-]{1,10}).*?([N|S]\s?\d{1,2}°?\s+\d{1,2}\.\d{1,3}'?).*?([E|W]\s?\d{1,3}°?\s+\d{1,2}\.\d{1,3}'?)\s(.*)


你可以在regex101中查看我的工作。
关注示例中的部分输出

GC8DH0G,,N 50° 50.456',W 001° 10.456',"Text to capture",,
Including line breaks and text, until the next GCcode
GC123GHF,,N 50 50.789,W 001 10.789,"etc.",,


唯一的额外要求是包括Longitude之后的所有多行文本,直到下面的GC代码,也包含在引用的捕获组4中。
因此,上述输出将变为

GC8DH0G,,N 50° 50.456',W 001° 10.456',"Text to capture
Including line breaks and text, until the next GCcode",,
GC123GHF,,N 50 50.789,W 001 10.789,"etc.",,


也就是说,所有文本,包括新行\n或\r\n都用引号括起来。

ffdz8vbo

ffdz8vbo1#

  • "...我的输入是来自不同来源的文本,唯一一致的是它们都包含一个代码,纬度和经度。

需要注意的是,资源通常会包括概述语法的文档。
无论如何,有不同的符号用于 * geographic coordinate * 值。
这里解析的是 DDM,或 “degrees,decimal-minutes”
随后,有 DMS,或 “度,分,秒”
另外,还有 DDdecimal degrees
这是一个 * 捕获模式 *。

  • Unicode**代码点 *,*U+00 b 0 *,是度数字符°
(GC[A-Z\d]+).*?([NS] \d+\x{00b0}? \d+(?:\.\d+)?[^,\s]?),([EW] \d+\x{00b0}? \d+(?:\.\d+)?[^,\s]?|$)?

个字符
此外,这里有一个 DMS 值的 * 模式 *。

(GC[A-Z\d]+).*?([NS] \d+\x{00b0}? \d+[^ ]? \d+(?:\.\d+)?[^,\s]+),([EW] \d+\x{00b0}? \d+[^ ]? \d+(?:\.\d+)?[^,\s]+|$)?

  • "...唯一的额外要求是包括Longitude之后的所有多行文本,直到下面的GC代码,也包含在引用的捕获组4中。

尝试以下操作。
从本质上讲,如果坐标后面跟的不是空白,那么就捕获内容,直到下一个 GC 代码。

(?: *$|(?s) *(.+?)\s*(?=GC[A-Z\d]+))


这里是re-factor。

(GC[A-Z\d]+).*?([NS] \d+\x{00b0}? \d+(?:\.\d+)?[^,\s]?),([EW] \d+\x{00b0}? \d+(?:\.\d+)?[^,\s]?|$)?(?: *$|(?s) *(.+?)\s*(?=GC[A-Z\d]+))


下面是捕获,我已经用\n替换了新行的分隔符。

GC8EYCQ, N 50° 50.123, W 001° 10.123, ""
GC8DH0G, N 50° 50.456', W 001° 10.456', "Text to capture\nIncluding line breaks and text, until the next GCcode"
GC123GHF, N 50 50.789, W 001 10.789, "More multiline text \nthat must be enclose in quotes\nNot just the first line of text to capture"
GC123ABC, N 50 50.987, W 001 10.987, ""
oprakyz7

oprakyz72#

尝试一下这个模式,使用PCRE自由空间模式和子例程定义。我借用了您的代码来定义纬度和经度(按照@Reilas的建议将°更改为\x{00b0})。

(?x) # make use of PCRE freespacing mode for better readability
(?(DEFINE) # define capture group behavior
  (?P<code_pattern> # GC code pattern
    GC # GC ...
    # ... followed by capital letters, digits and "-" 1 trough 10 times
    [A-Z0-9-]{1,10} 
  ) # end code_pattern
  # pattern to match lat and long locations
  (?P<location_pattern>
    \s? # optional space
    \d{1,3} # one or two digits
    \x{00b0}? # unicode of "°"
    \s+ # any number of spaces
    \d{1,2} # 1 or 2 digits
    \. # literal "."
    \d{1,3} # 1 through 2 digits
    '?
  ) # end location_pattern
  (?P<latitude_pattern>
    [NS] # "N" or "S"
    (?P>location_pattern)
  )
  # longitude analogous to
  (?P<longitude_pattern>
    [EW] # "E" or "W"
    (?P>location_pattern)
  )
  # pattern checking if current line contains a code
  (?P<check_for_code>
    (?!.*(?P>code_pattern))
  )
  # pattern to match notes
  (?P<notes_pattern>
    # note is only eligible if line has no more code
    (?P>check_for_code)
    .* # matches line 
    (?: # possibly ...
      \n # ... match new lines ...
      (?P>check_for_code) # ... if they contain no code
      .* # matches line
    )*
  ) # end notes_pattern
) # end definitions

#### ACTUAL PATTERN ####

# match unwanted initial characters so they can be replaced by an empty string
.* 
(?P<Code>(?P>code_pattern)) # capture Code
.*? # followed (lazily) by anything
(?P<Latitude>(?P>latitude_pattern)) # capture Latitude
.*? # followed (lazily) by anything
(?P<Longitude>(?P>longitude_pattern)) # capture Longitude
\s? # by optional space
(?P<Notes>(?P>notes_pattern))? # capture Notes (optional)

字符串
替换为:

$Code,,$Latitude,$Longitude,"$Notes",,\n


参见https://regex101.com/r/2a7AG7/latest
如果你需要删除CSV中的空行,进一步用空字符串替换^$\n
参见https://regex101.com/r/Mj6rH7/latest

相关问题