在官方文书、票据中,货币金额的写法五花八门,比如,最近在处理环保处罚的数据时,发现各地行政在描述处罚内容中对处罚金额的写法也花样繁多,形式各异。

  • 1.违法排放大气污染物环境违法行为处以人民币壹拾伍万元(¥150000.00)罚款;2.违法排放水污染物环境违法行为处以人民币叁拾伍万元(¥350000.00)罚款。两项合并处罚人民币伍拾万元(¥500000.00)罚款。
  • 2018年4月14日至4月15、17日、19日至28日共计13天,每天处以罚款壹拾万元,共计处以罚款壹佰叁拾万元整。同时,责令你公司立即改正以上违法行为
  • 罚款:20万元;其他:责令改正违法行为
  • 罚款人民币拾万元整(?100,000元)
  • 罚款人民币35,000元
  • 罚款人民币2,000元
  • 罚款人民币0.232万元

下面hive脚本就针对上面的这几种情况,统一对其处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
with punish_money AS (
select id, cid,
regexp_replace(
regexp_replace(
regexp_replace(
regexp_replace(regexp_replace(regexp_replace(regexp_replace(
translate(punish_moneny, '零〇一二三四五六七八九壹弍叁肆伍陆柒捌玖', '00123456789123456789'),
'(?<=[0-9])((千万)|(千亿))(?=[0-9])','000'),
'(?<=[0-9])((百万)|(百亿))(?=[0-9])','00'),
'(?<=[0-9])((十万)|(十亿))(?=[0-9])','0'),
'(?<=[0-9])[十|百|千|万|亿](?=[0-9])', ''),
'(?<![0-9])十(?![0-9])', '10'),
'(?<![0-9])十(?=[0-9])', '1'),
'(?<=[0-9])十(?![0-9])', '0')
as pm,
punish_moneny,
regexp_replace(
regexp_replace(
regexp_replace(
regexp_replace(regexp_replace(regexp_replace(regexp_replace(
translate(total_pm, '零〇一二三四五六七八九壹弍叁肆伍陆柒捌玖', '00123456789123456789'),
'(?<=[0-9])((千万)|(千亿))(?=[0-9])','000'),
'(?<=[0-9])((百万)|(百亿))(?=[0-9])','00'),
'(?<=[0-9])((十万)|(十亿))(?=[0-9])','0'),
'(?<=[0-9])[十|百|千|万|亿](?=[0-9])', ''),
'(?<![0-9])十(?![0-9])', '10'),
'(?<![0-9])十(?=[0-9])', '1'),
'(?<=[0-9])十(?![0-9])', '0')
as total_pm
from (
select cid, id,
regexp_replace(
regexp_extract(
punish_content,
'(((?<=((共计|合并)处).{0,100})([〇一二二三四五六七八九十百千万0-9\.,,]+)(?=元))|((?<=([处罚|罚款|罚])?)([〇一二二三四五六七八九十百千万0-9\.,,]+)(?=元))|((?<=处.{0,100})([〇一二二三四五六七八九十百千万0-9\.,,]+)(?=罚款)))', 1),
',|,', '')as punish_moneny,
regexp_extract(punish_content, '((?<=((共计|合并)处).{0,100})([〇一二二三四五六七八九十百千万0-9\.,,]+)(?=元))', 1) as total_pm, punish_content
from (
SELECT id, cid, translate(punish_content, '零壹弍贰叁肆伍陆柒捌玖拾佰仟萬', '〇一二二三四五六七八九十百千万') as punish_content
from dwd_creditrisk_xy_company_jyfx.company_jyfx_hbcf
where punish_content rlike '罚'
-- 加分区
and dayno = '2023-05-13'
) t
) tt
where tt.punish_moneny !=''
) ,
cal_total_pm as(
SELECT id,cid, pm, punish_moneny, total_pm,
case
when pm rlike '千亿' then cast(money * 100000000000 as decimal(16,2))
when pm rlike '百亿' then cast(money * 10000000000 as decimal(16,2))
when pm rlike '十亿' then cast(money * 1000000000 as decimal(16,2))
when pm rlike '亿' then cast(money * 100000000 as decimal(16,2))
when pm rlike '千万' then cast(money * 10000000 as decimal(16,2))
when pm rlike '百万' then cast(money * 1000000 as decimal(16,2))
when pm rlike '十万' then cast(money * 100000 as decimal(16,2))
when pm rlike '万' then cast(money * 10000 as decimal(16,2))
when pm rlike '千' then cast(money * 1000 as decimal(16,2))
when pm rlike '百' then cast(money * 100 as decimal(16,2))
when pm rlike '十' then cast(money * 10 as decimal(16,2))
else cast(money as decimal(16,2))
end as money,
case
when total_pm rlike '千亿' then cast(total_money * 100000000000 as decimal(16,2))
when total_pm rlike '百亿' then cast(total_money * 10000000000 as decimal(16,2))
when total_pm rlike '十亿' then cast(total_money * 1000000000 as decimal(16,2))
when total_pm rlike '亿' then cast(total_money * 100000000 as decimal(16,2))
when total_pm rlike '千万' then cast(total_money * 10000000 as decimal(16,2))
when total_pm rlike '百万' then cast(total_money * 1000000 as decimal(16,2))
when total_pm rlike '十万' then cast(total_money * 100000 as decimal(16,2))
when total_pm rlike '万' then cast(total_money * 10000 as decimal(16,2))
when total_pm rlike '千' then cast(total_money * 1000 as decimal(16,2))
when total_pm rlike '百' then cast(total_money * 100 as decimal(16,2))
when total_pm rlike '十' then cast(total_money * 10 as decimal(16,2))
else cast(total_money as decimal(16,2))
end as total_money
from (
SELECT id,
cid,
pm,
punish_moneny,
total_pm,
cast(regexp_extract(pm, '([0-9\.]+)', 1) as decimal(16,4)) as money,
cast(regexp_extract(total_pm, '([0-9\.]+)', 1) as decimal(16,4)) as total_money
from punish_money
) t
)
SELECT id,cid, punish_moneny as pm, if(total_money is not null and total_money > money, total_money, money) as punish_amt
FROM cal_total_pm

下面就针对上面脚本中用到的几个函数和正则表达式做一个简单的介绍,以帮助基础薄弱的朋友们理解这段脚本。

  • translate:该函数的英文含义就是“翻译”,很直白地说,就是映射转换。需要传入三个参数,第一个参数是原文本,第二个参数是需要替换的字符,第三个是替换的结果字符。特别注意,第二个参数和第三个参数是一一对应的。

  • regexp_replace:正则替换函数。第一个参数是原文,第二个参数是需要替换的正则表达式,第三个参数则是替换的值。

  • regexp_extract:正则抽取函数。该函数同样需要三个参数,第一个原文,第二个参数是正则表达式,第三个参数是抽取正则表达式的第几个括号中的值。每遇到一个“(”就算一个分组,类似 java 中的 Matcher#group(int g) 函数。

  • 正向断言和负向断言

    1. (?=pattern):正向先行断言,表示匹配位置后面必须紧跟着满足 pattern 的字符串,但不包括这个字符串在匹配结果中,RegExp1(?=RegExp2) 匹配后面是RegExp2 的 RegExp1。

    2. (?!pattern):负向先行断言,表示匹配位置后面不能紧跟着满足 pattern 的字符串,也不包括这个字符串在匹配结果中,RegExp1(?!RegExp2) 匹配后面不是RegExp2 的 RegExp1。

    3. (?<=pattern):正向后行断言,表示匹配位置前面必须是满足 pattern 的字符串,但不包括这个字符串在匹配结果中,(?<=RegExp2)RegExp1 匹配前面是RegExp2 的 RegExp1。

    4. (?<!pattern):负向后行断言,表示匹配位置前面不能是满足 pattern 的字符串,也不包括这个字符串在匹配结果中,(?<!RegExp2)RegExp1 匹配前面不是RegExp2 的 RegExp1。

虽然这个写法还不能满足所有的金额的处理,但常见的格式基本满足,具体情况,可以根据具体的格式做一些调整即可。