楼主: Rock2000
7283 11

[程序分享] 如何读取不等长度不等数量带分隔符字符串 [推广有奖]

  • 1关注
  • 24粉丝

已卖:6892份资源

学术权威

23%

还不是VIP/贵宾

-

威望
1
论坛币
104790 个
通用积分
51.9656
学术水平
55 点
热心指数
74 点
信用等级
48 点
经验
23510 点
帖子
520
精华
0
在线时间
10924 小时
注册时间
2004-5-27
最后登录
2025-11-12

楼主
Rock2000 发表于 2013-6-18 23:27:04 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
如何读取不等长度不等数量带分隔符字符串?比如有如下字符数据
  1. 001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle002 IBM,Lenovo003 GIGABYTE,MSI,ACER,DELL
复制代码
现要统计各词“ASUS”、“IBM”等出现频率,怎样实现?

一般来说我们的思路是各行数据中所有的词读入到同一变量中,怎么实现你,上网查找,找到一台湾网友的解决方法,现在分享给大家,欢迎用其它解决方法,请分享在此。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:字符串 BlackBerry Lenovo Berry Black 字符串 如何

本帖被以下文库推荐

沙发
Rock2000 发表于 2013-6-18 23:29:07

上网查找,发现一台湾网友的解决方案,方法如下:



解开字符串内的逗点区隔文字
http://r97846001.blog.ntu.edu.tw/2011/08/27/pull-all-words-from-string/

有接触数据的捧由,应该有看过一种coding方式是将数值/文字链接在同一个字段中,例如一位研究员将一位个案在五次不同时间测量的血压值输入到excel档案中

128,130,122,140,126

在实际纳入分析时,比方说计算五次血压平均

这字段总得要解开成为五列数值吧!

参考过SAS help后,以下说明将以这串品牌名称作范例

分享作法一给各位,如果有其他方法也欢迎提供讨论

string=ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle

目标是将该字符串依照逗号解开成为8个rows

关于字符串处理的函数,用力回想后跑出了:SCAN、COMPRESS、FIND、CAT等相关函数

其中,扫描一个字符串、指定位置后并且输出的功能,非SCAN莫属

SCAN函数范例:string=’ABC.DEF(X=Y)’;  word=scan(string, 3); 执行后的word值为X=Y

但是,SCAN还不足以解决现在的问题

因为需要逗点分隔之间的所有单字,没错吧!

介绍一个CALL ROUTINE的函数:CALL SCAN

CALL SCAN(string, n, position, length, <delimiters>);

  • string: 通常是一个变项名称, 例如上面的string
  • n: 数字, 该字符串内用户希望撷取出多少字词(word), n为正数表示左到右扫, 负数表示从右到左扫, |n|大于string内的字词数则回传零
  • position: 回传该字词所在起始位置
  • length: 回传该字词的长度
  • <delimiters>: 选择性的option, 可接受空白, < ( + & ! $ * ) ; ^ – / , % |等做为区隔符号

注意:使用CALL SCAN后要取得字词,需要使用SUBSTRN函数

而SUTSTRN利用CALL SCAN得到的字词起始位置与长度再做撷取动作,并非CALL SCAN完成整个目标喔!

这个范例应用到DO LOOP的概念来做重复扫字词的动作

巧妙搭配output完成字词输出


data test;
      input id $ string $60.;/*由于字符串很长, 指定长度$60,$表示的意思应该..不陌生吧, 表示非数值*/
      drop string;
      do i=1 to 99;/*由于要让他输出每次扫到的字词, 随意订个99~在此可以完整扫出*/
     call scan ( string, i, position , length , "," );/*以逗点做区隔符号, 由左至右启动*/
           if not position then leave;/*若没有扫到位置,即跳出*/
          name=substrn ( string ,  position ,   length );/*将个别的字词放到变项name里*/
         output;/*在此马上输出字词结果*/
   end;/*有do就有end, 请不要忘记*/
datalines;
001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle
002 IBM,Lenovo
003 GIGABYTE,MSI,ACER,DELL
;
proc print data=test;/*在output窗口输出结果*/
run;
proc freq data=test;
table name;
run;



延伸函数:CALL SCANQ (最大的差别是此函数不考虑区隔符号)





藤椅
maxun333 发表于 2013-6-18 23:42:18
同求啊,为国产主义服务

板凳
可~乐 发表于 2013-6-19 11:38:30
countc+scan函数也可以很好的解决
data test;
input id $ string $60.;/*由于字符串很长, 指定长度$60,$表示的意思应该..不陌生吧, 表示非数值*/
        length=countc(string,",")+1;
        do i=1 to length;
                new_name=scan(string,i,",");
                output;
        end;
        keep id new_name;
datalines;
001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle
002 IBM,Lenovo
003 GIGABYTE,MSI,ACER,DELL
;
run;
已有 1 人评分学术水平 热心指数 收起 理由
Rock2000 + 1 + 1 精彩帖子

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

报纸
Rock2000 发表于 2013-6-19 21:15:30
可~乐 发表于 2013-6-19 11:38
countc+scan函数也可以很好的解决
data test;
input id $ string $60.;/*由于字符串很长, 指定长度$60,$表 ...
不错,还有无其它方法吗?

地板
yongyitian 发表于 2013-6-19 22:06:54
做一点小小的该动,可以不用调整循环次数。

data test;
      input id $ string $60.;
      drop string n i position length;
      i = 1;
  do until (n=0);
     call scan ( string, i, position , length , "," );
       if not position then n=0;
      else     name=substrn ( string ,  position ,   length );
         output;
          i+1;
   end;
datalines;
001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle
002 IBM,Lenovo
003 GIGABYTE,MSI,ACER,DELL
;
已有 1 人评分学术水平 热心指数 收起 理由
Rock2000 + 1 + 1 热心帮助其他会员

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

7
老师她摸我 发表于 2013-6-19 22:31:41
  1. data test;
  2.        input id $ string $60.;
  3.        i = 1;
  4.        do until(scan(string,i,',')=' ');
  5.                _name=scan(string,i,',');
  6.                       output;
  7.                i+1;
  8.         end;
  9.         keep id _:;
  10. datalines;
  11. 001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle
  12. 002 IBM,Lenovo
  13. 003 GIGABYTE,MSI,ACER,DELL
  14. ;
复制代码
已有 1 人评分学术水平 热心指数 收起 理由
Rock2000 + 1 + 1 热心帮助其他会员

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

欢迎加入SAS群:144839730-蜗牛

8
Imasasor 发表于 2013-6-19 22:50:44
  1. data a;
  2. infile datalines dlm=", ";
  3. input x:$15. @@;
  4. if compress(x,"","d")^="";
  5. cards;
  6. 001 ASUS,CORSAIR,GIGABYTE,MSI,ACER,BlackBerry,intel,Shuttle
  7. 002 IBM,Lenovo
  8. 003 GIGABYTE,MSI,ACER,DELL
  9. ;
  10. run;
  11. proc freq data=a order=freq;
  12. table x/out=b;
  13. run;
复制代码
兄弟们,为什么不在读取的时候就把它分开呢?
欢迎加入亚太地区第一R&Python数据挖掘群: 251548215;

9
Rock2000 发表于 2013-6-19 23:14:11
Imasasor 发表于 2013-6-19 22:50
兄弟们,为什么不在读取的时候就把它分开呢?
版主,我原来也是想用infile +dlm参数的,不过,这里还差些少,ID变量没有了。
我是想这样的
  1. Obs id _name
  2. 1 001 ASUS
  3. 2 001 CORSAIR
  4. 3 001 GIGABYTE
  5. 4 001 MSI
  6. 5 001 ACER
  7. 6 001 BlackBerry
  8. 7 001 intel
  9. 8 001 Shuttle
  10. 9 002 IBM
  11. 10 002 Lenovo
  12. 11 003 GIGABYTE
  13. 12 003 MSI
  14. 13 003 ACER
  15. 14 003 DELL
复制代码
程序咋修改?

10
Imasasor 发表于 2013-6-20 13:43:09
Rock2000 发表于 2013-6-19 23:14
版主,我原来也是想用infile +dlm参数的,不过,这里还差些少,ID变量没有了。
我是想这样的程序咋修改? ...
我也不会啊,好像没什么好办法,还是拆分吧
欢迎加入亚太地区第一R&Python数据挖掘群: 251548215;

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-30 23:49