※ 引述《PILIPALAPON (pilipalapon)》之铭言:
: [问题类型]:
: 程式咨询
: [软件熟悉度]:
: 入门
: [问题叙述]:
: 资料档如下
: Addr
: 宜兰县数学镇数学里10邻数学路100巷16之2号
: 基隆市太阳区太阳里17邻太阳三街223之2号十九楼
: 基隆市白云区白云里20邻白云三街59号十楼之1
: 新竹市海洋区海洋里13邻海洋路29号六楼
: 台北市小明区小名里20邻小名路222号二十楼
: 新北市语文区语文里17邻语文路221号二十九楼之5
: 宜兰县飞机镇飞机里3邻飞机路73号
: 新北市红色区红色里15邻红色路四段15号之4十七楼
: 若“楼”前面有国字数字,需先转成数字,再将每一个住址里的数字全部抓出来。
:
这个问题除了中文数字外,还需要处理全型的数字(已问过原PO,后面确实是全型数字)
我这里的顺序是先处理全型的数字,才处理中文数字
当然也可以反过来,两个不影响
好读版:http://pastebin.com/srDz11gP
全型转成半型的想法是这样:
先行知识:字串可以转成raw bytes的型式,多个16进位的数字表示
你可以试试看 charToRaw("123") 会出现 [1] 31 32 33
charToRaw("123") 会出现 [1] a2 b0 a2 b1 a2 b2
所以全角数字会占去两个16进位,可以稍微测试一下:
charToRaw("0123456789")
[1] a2 af a2 b0 a2 b1 a2 b2 a2 b3 a2 b4 a2 b5 a2 b6 a2 b7 a2 b8
可以看到全型的0123456789 开头都是 a2 而结尾是af到b8
把af到b8转成数字就是 175~184
因此,先把a2找出来,再将确定后一位是否为175~184 (全角数字)
之后再把第二个数字做位移(减去127),然后把第一个数字去掉
这样转换就完成了
PS: 减去127的原因是 as.integer(charToRaw("0"))是 48
as.integer(charToRaw("0")[2])是 175 两个相差的值是127...
至于中文数字转阿拉伯数字则是参考这篇的python code:
http://www.cnblogs.com/kaituorensheng/p/3586942.html
address <- c("宜兰县数学镇数学里10邻数学路100巷16之2号",
"基隆市太阳区太阳里17邻太阳三街223之2号十九楼",
"基隆市白云区白云里20邻白云三街59号十楼之1",
"新竹市海洋区海洋里13邻海洋路29号六楼",
"台北市小明区小名里20邻小名路222号二十楼",
"新北市语文区语文里17邻语文路221号二十九楼之5",
"宜兰县飞机镇飞机里3邻飞机路73号",
"新北市红色区红色里15邻红色路四段15号之4十七楼")
library(magrittr)
library(plyr)
library(stringr)
library(stringi)
address_converted <- sapply(address, function(x){
raw_address <- charToRaw(x)
loc_maybe_fullwidth_digits <- which(raw_address == "a2")
second_loc <- raw_address[loc_maybe_fullwidth_digits+1] %>% as.integer
loc_fullwidth_digits <- loc_maybe_fullwidth_digits[second_loc >= 175 &
second_loc <= 184] + 1
raw_address[loc_fullwidth_digits] <- raw_address[loc_fullwidth_digits] %>%
as.integer %>% '-'(127) %>% as.raw
return(rawToChar(raw_address[setdiff(1:length(raw_address),
loc_fullwidth_digits-1)]))
}) %>% `names<-`(NULL)
# [1] "宜兰县数学镇数学里10邻数学路100巷16之2号"
# [2] "基隆市太阳区太阳里17邻太阳三街223之2号十九楼"
# [3] "基隆市白云区白云里20邻白云三街59号十楼之1"
# [4] "新竹市海洋区海洋里13邻海洋路29号六楼"
# [5] "台北市小明区小名里20邻小名路222号二十楼"
# [6] "新北市语文区语文里17邻语文路221号二十九楼之5"
# [7] "宜兰县飞机镇飞机里3邻飞机路73号"
# [8] "新北市红色区红色里15邻红色路四段15号之4十七楼"
chinese2digits <- function(x){
vals <- sapply(str_split(x, "")[[1]], function(chi_digit){
mapvalues(chi_digit, c("零", "一", "二", "三", "四", "五", "六", "七",
"八", "九", "十", "百", "千", "万", "亿"),
c(0:10, 10^c(2,3,4,8)), FALSE)
}) %>% as.integer
digit_output <- 0
base_term <- 1
for (i in rev(seq_along(vals)))
{
if (vals[i] >= 10 && i == 1)
{
base_term <- ifelse(vals[i] > base_term, vals[i], base_term * vals[i])
digit_output <- digit_output + vals[i]
} else if (vals[i] >= 10)
{
base_term <- ifelse(vals[i] > base_term, vals[i], base_term * vals[i])
} else
{
digit_output <- digit_output + base_term * vals[i]
}
}
return(digit_output)
}
## test
# chinese2digits("一百五十二") # 152
# chinese2digits("一亿零八万零三百二十三") # 100080323
# chinese2digits("十九") # 19
address_converted2 <- sapply(address_converted, function(x){
pattern_starts <- "[零一二三四五六七八九十百千万亿]+楼"
if (!str_detect(x, pattern_starts))
return(x)
stairs <- str_extract(x, pattern_starts)
x <- str_replace(x, str_c("(\\d+)(", pattern_starts, ")"), "\\1, \\2")
x <- str_replace(stairs, "楼", "") %>% chinese2digits %>% str_c("楼") %>%
{str_replace(x, stairs, .)}
return(x)
}) %>% `names<-`(NULL)
# [1] "宜兰县数学镇数学里10邻数学路100巷16之2号"
# [2] "基隆市太阳区太阳里17邻太阳三街223之2号19楼"
# [3] "基隆市白云区白云里20邻白云三街59号10楼之1, "
# [4] "新竹市海洋区海洋里13邻海洋路29号6楼"
# [5] "台北市小明区小名里20邻小名路222号20楼"
# [6] "新北市语文区语文里17邻语文路221号29楼之5, "
# [7] "宜兰县飞机镇飞机里3邻飞机路73号"
# [8] "新北市红色区红色里15邻红色路四段15号之4, 17楼"
sapply(address_converted2, str_extract_all, pattern = "\\d+")
# $`宜兰县数学镇数学里10邻数学路100巷16之2号`
# [1] "10" "100" "16" "2"
#
# $基隆市太阳区太阳里17邻太阳三街223之2号19楼
# [1] "17" "223" "2" "19"
#
# $`基隆市白云区白云里20邻白云三街59号10楼之1, `
# [1] "20" "59" "10" "1"
#
# $新竹市海洋区海洋里13邻海洋路29号6楼
# [1] "13" "29" "6"
#
# $台北市小明区小名里20邻小名路222号20楼
# [1] "20" "222" "20"
#
# $`新北市语文区语文里17邻语文路221号29楼之5, `
# [1] "17" "221" "29" "5"
#
# $宜兰县飞机镇飞机里3邻飞机路73号
# [1] "3" "73"
#
# $`新北市红色区红色里15邻红色路四段15号之4, 17楼`
# [1] "15" "15" "4" "17"