文本解析查找具有表示基本单位(例如平方米、sq.m、m^2、m2 等)的不同字符串的数据
Text parsing looking for data with different strings expressing the base units (ex. square meters, sq.m, m^2, m2, etc.)
我正在尝试抓取存储在各种 txt 文件中的许多住宅物业的面积编号(平方米或平方英尺)。
面积几乎总是通过指定单位来表示,无论是在公制系统中(长度以米为基本单位表示)还是在英国帝国系统中(长度以英尺为基本单位表示)通过给出一个数字按单位。
面积单位有多种字符串表示,例如"square meters"可以显示为"sqm"、"sq.m"、"sq m"、"square m"、"sq.meters"、"m^2"、"m2"等(不同字母的大小写也可以变化)。
我拥有的一些 TXT 示例(我只复制了包含我感兴趣的数据的行,清理了其余部分):
1)
...
Approximate Gross Internal Area = 40.1 sq m / 432 sq ft Re’
...
2)
...
Total area: approx. 37.3 sq. metres (402.0 sq. feet)
...
3)
...
Approx. Gross Internal Area *
413Ft’-38.37M’
...
我的目标是解析每个 txt 文件,获取平方米(或平方英尺)数并存储它。
我已经开始研究 Python 常规 Expressions/RegEx、模式匹配、文本处理和文本解析工具,但我决定搁置研究,看看是否有人曾经有一个相似的目标。
您认为解决此特定任务的最有效方法是什么?通过使用正则表达式、文本解析或什么?
我很愿意使用其他脚本语言(PERL、Ruby 等),如果它们更适合的话。
如果我没理解错的话,你想构建一个文本解析器来执行数据库插入(我想)。
我认为这是一项简单的任务,可以用您建议的所有语言实现。他们之间没有特定的收益(偏好问题除外)。
我建议您采用符合以下标准的语言:
- 您的生产服务器是否提供解释器?
- 您打算永远维护此代码,还是打算在不久的将来由其他人来维护它?
- 你
- 选择您觉得更舒服的语言
- 其他人
- 选择一种在您所在地区更容易找到工作人员的语言。
顺便说一下,我会选择 Python。它随处可用。
您可以使用 Marpa::R2, a Perl interface to Marpa,一个通用的 BNF 解析器。
数据可以在BNF中描述为this ::= that
(~
运算符定义词法规则)。
解析器returns 一种数据结构([ id, child1, child2 ... ]
格式的数组),可以从中提取区域。
您还可以将 semantic actions 定义为 Perl sub
在同一个或单独的包中处理数据。
下面是一个基于您的数据的示例脚本及其输出。
脚本:
use 5.010;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Deepcopy = 1;
use Marpa::R2;
my $g = Marpa::R2::Scanless::G->new( { source => \(<<'END_OF_SOURCE'),
:default ::= action => [ name, value]
lexeme default = action => [ name, value] latm => 1
<area data> ::= <area data item>+
<area data item> ::= area
<area> ::= float unit
float ~ int '.' int
float ~ int '.'
float ~ int
int ~ [\d]+
unit ~ 'sqm' | 'sq.m' | 'sq m' | 'square m' | 'sq.meters' | 'm^2' | 'm2'
:discard ~ whitespace
whitespace ~ [\s]+
END_OF_SOURCE
} );
my $input = <<EOI;
40.2 sq m
40 sqm
40. sq.m
40.2 sq m
40.2 square m
40.2 sq.meters
40.2 m^2
40.2 m2
EOI
say Dumper ${ $g->parse( $input ) };
输出:
[
'area data',
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40'
],
[
'unit',
'sqm'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.'
],
[
'unit',
'sq.m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'square m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq.meters'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'm^2'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'm2'
]
]
]
]
虽然使用正则表达式没有错。它们以您提到的所有语言提供。
BNF 可以更多readable/maintainable,这在处理非结构化文本时很好。
OP 通过电子邮件要求此答案。
如果您能够通过 IronPython 或类似工具使用 .NET 库,那么您可能会在 Units.NET 中找到用于解析您的区域字符串的方法。或者简单地复制其解析正则表达式并根据您的需要进行修改。
Units.NET 可以解析大多数常用单位的值+单位字符串表示,包括公制和英制。
示例:
double a = Area.Parse("5 m²").SquareMeters; // 5.0
Area.Parse("0.092903m²").SquareFeet; // ~1.0
Area.Parse("50000 cm²").ToString(); // "5 m²", sq.m is default unit
Area.Parse("1ft²").SquareMeters; // 0.092903
Area.Parse("1 in²").SquareCentimeters; // 6.4516
见Area.json for all area units and their abbreviations. Please note that SquareMeter currently only supports "m²"
, but you can add more abbreviations like "m^2"
, "sq.m"
, "sqm"
and so on at runtime via UnitSystem.MapUnitToAbbreviation()
and we happily accept pull requests to add more unit abbreviations to the library. See example。
这是我为解决该问题而编写的 Python RegEx 代码,以备不时之需:
unit_pattern = re.compile(r"[+-]? *((?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)\s*(square meters|square metres|square meter|square metre|square m|square mt|sqmt|sq mt|sq.mt|sq. mt|sqm|sq m|sq.m|sq. m|meters2|metres2|meter2|metre2|mt2|m2)", re.IGNORECASE)
for i, line in enumerate(open('/Users/USERNAME/text.txt')):
for match in re.finditer(unit_pattern, line):
print 'Found on line %s: %s' % (i+1, match.groups())
应用于以下 txt 文件:
eleventh Floor
Approx. 37.3 sq. metres (402.0 sq. feet)
Living
Room
7.06m x 4.04m
(23'2" x 13'3")
Bedroom
Area
Shower
Room
Total area: approx. 37.3 sq. metres (402.0 sq. feet)
For illustrative purposes only — Not to scale.
Plan produced using P|anUp.
给出以下输出:
Found on line 2: ('37.3', 'sq. m')
Found on line 16: ('37.3', 'sq. m')
我正在尝试抓取存储在各种 txt 文件中的许多住宅物业的面积编号(平方米或平方英尺)。
面积几乎总是通过指定单位来表示,无论是在公制系统中(长度以米为基本单位表示)还是在英国帝国系统中(长度以英尺为基本单位表示)通过给出一个数字按单位。
面积单位有多种字符串表示,例如"square meters"可以显示为"sqm"、"sq.m"、"sq m"、"square m"、"sq.meters"、"m^2"、"m2"等(不同字母的大小写也可以变化)。
我拥有的一些 TXT 示例(我只复制了包含我感兴趣的数据的行,清理了其余部分):
1)
...
Approximate Gross Internal Area = 40.1 sq m / 432 sq ft Re’
...
2)
...
Total area: approx. 37.3 sq. metres (402.0 sq. feet)
...
3)
...
Approx. Gross Internal Area *
413Ft’-38.37M’
...
我的目标是解析每个 txt 文件,获取平方米(或平方英尺)数并存储它。
我已经开始研究 Python 常规 Expressions/RegEx、模式匹配、文本处理和文本解析工具,但我决定搁置研究,看看是否有人曾经有一个相似的目标。
您认为解决此特定任务的最有效方法是什么?通过使用正则表达式、文本解析或什么?
我很愿意使用其他脚本语言(PERL、Ruby 等),如果它们更适合的话。
如果我没理解错的话,你想构建一个文本解析器来执行数据库插入(我想)。
我认为这是一项简单的任务,可以用您建议的所有语言实现。他们之间没有特定的收益(偏好问题除外)。
我建议您采用符合以下标准的语言:
- 您的生产服务器是否提供解释器?
- 您打算永远维护此代码,还是打算在不久的将来由其他人来维护它?
- 你
- 选择您觉得更舒服的语言
- 其他人
- 选择一种在您所在地区更容易找到工作人员的语言。
- 你
顺便说一下,我会选择 Python。它随处可用。
您可以使用 Marpa::R2, a Perl interface to Marpa,一个通用的 BNF 解析器。
数据可以在BNF中描述为this ::= that
(~
运算符定义词法规则)。
解析器returns 一种数据结构([ id, child1, child2 ... ]
格式的数组),可以从中提取区域。
您还可以将 semantic actions 定义为 Perl sub
在同一个或单独的包中处理数据。
下面是一个基于您的数据的示例脚本及其输出。
脚本:
use 5.010;
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Deepcopy = 1;
use Marpa::R2;
my $g = Marpa::R2::Scanless::G->new( { source => \(<<'END_OF_SOURCE'),
:default ::= action => [ name, value]
lexeme default = action => [ name, value] latm => 1
<area data> ::= <area data item>+
<area data item> ::= area
<area> ::= float unit
float ~ int '.' int
float ~ int '.'
float ~ int
int ~ [\d]+
unit ~ 'sqm' | 'sq.m' | 'sq m' | 'square m' | 'sq.meters' | 'm^2' | 'm2'
:discard ~ whitespace
whitespace ~ [\s]+
END_OF_SOURCE
} );
my $input = <<EOI;
40.2 sq m
40 sqm
40. sq.m
40.2 sq m
40.2 square m
40.2 sq.meters
40.2 m^2
40.2 m2
EOI
say Dumper ${ $g->parse( $input ) };
输出:
[
'area data',
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40'
],
[
'unit',
'sqm'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.'
],
[
'unit',
'sq.m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'square m'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'sq.meters'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'm^2'
]
]
],
[
'area data item',
[
'area',
[
'float',
'40.2'
],
[
'unit',
'm2'
]
]
]
]
虽然使用正则表达式没有错。它们以您提到的所有语言提供。
BNF 可以更多readable/maintainable,这在处理非结构化文本时很好。
OP 通过电子邮件要求此答案。
如果您能够通过 IronPython 或类似工具使用 .NET 库,那么您可能会在 Units.NET 中找到用于解析您的区域字符串的方法。或者简单地复制其解析正则表达式并根据您的需要进行修改。
Units.NET 可以解析大多数常用单位的值+单位字符串表示,包括公制和英制。
示例:
double a = Area.Parse("5 m²").SquareMeters; // 5.0
Area.Parse("0.092903m²").SquareFeet; // ~1.0
Area.Parse("50000 cm²").ToString(); // "5 m²", sq.m is default unit
Area.Parse("1ft²").SquareMeters; // 0.092903
Area.Parse("1 in²").SquareCentimeters; // 6.4516
见Area.json for all area units and their abbreviations. Please note that SquareMeter currently only supports "m²"
, but you can add more abbreviations like "m^2"
, "sq.m"
, "sqm"
and so on at runtime via UnitSystem.MapUnitToAbbreviation()
and we happily accept pull requests to add more unit abbreviations to the library. See example。
这是我为解决该问题而编写的 Python RegEx 代码,以备不时之需:
unit_pattern = re.compile(r"[+-]? *((?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)\s*(square meters|square metres|square meter|square metre|square m|square mt|sqmt|sq mt|sq.mt|sq. mt|sqm|sq m|sq.m|sq. m|meters2|metres2|meter2|metre2|mt2|m2)", re.IGNORECASE)
for i, line in enumerate(open('/Users/USERNAME/text.txt')):
for match in re.finditer(unit_pattern, line):
print 'Found on line %s: %s' % (i+1, match.groups())
应用于以下 txt 文件:
eleventh Floor
Approx. 37.3 sq. metres (402.0 sq. feet)
Living
Room
7.06m x 4.04m
(23'2" x 13'3")
Bedroom
Area
Shower
Room
Total area: approx. 37.3 sq. metres (402.0 sq. feet)
For illustrative purposes only — Not to scale.
Plan produced using P|anUp.
给出以下输出:
Found on line 2: ('37.3', 'sq. m')
Found on line 16: ('37.3', 'sq. m')