作者celestialgod (天)
看板R_Language
标题Re: [问题] 字串处理-抓取字串中的数字
时间Thu Jun 16 00:00:54 2016
※ 引述《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"
--
R资料整理套件系列文:
magrittr #1LhSWhpH (R_Language) http://tinyurl.com/j3ql84c
data.table #1LhW7Tvj (R_Language) http://tinyurl.com/hr77hrn
dplyr(上) #1LhpJCfB (R_Language) http://tinyurl.com/jtg4hau
dplyr(下) #1Lhw8b-s (R_Language)
tidyr #1Liqls1R (R_Language) http://tinyurl.com/jq3o2g3
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 211.76.63.212
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/R_Language/M.1466006460.A.4DC.html
1F:推 PILIPALAPON: 感谢~~ 06/16 01:45
※ 编辑: celestialgod (140.109.74.87), 06/16/2016 09:55:31
2F:推 fish0331: 推一个,但数字中文转换还是有限制,比如没有「亿」以上 08/20 13:30
3F:→ fish0331: 的对应转换,以及数字太大在电脑中计算产生溢位的疑虑。 08/20 13:30
4F:→ fish0331: 不知道後来有没有更新的手法。另外函式chinese2digits 08/20 13:30
5F:→ fish0331: 中for里的第一个if,有一点小错误,应该是digit_output 08/20 13:30
6F:→ fish0331: <-digit_output + base_term。可以用十二万零一百做测 08/20 13:30
7F:→ fish0331: 试:) 08/20 13:30