标题:分享:截取字N长度的字符串
取消只看楼主
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
结帖率:98.96%
已结贴  问题点数:10 回复次数:6 
分享:截取字N长度的字符串

CLEAR
Str1 = "12345人发可个方和方经品他三方登山泛水多福多寿辅导费对方012345678901nLen1-1456789"

? CutStr(str1,31)
? CutStr(31,31)

*!* 截取 N 长度的字符串,中英文通杀

FUNCTION CutStr(cStr1,nLen1)
LOCAL N1,cStr2
*!* 处理参数
IF TYPE("cStr1") # "C"
   IF  EMPTY(cStr1)
       cStr1 = ""
   ELSE
       cStr1 = ALLTRIM(TRANSFORM(cStr1))
   ENDIF
ENDIF
N1 = LEN(cStr1)
IF TYPE("nLen1") # "N"
   nLen1 = N1
ELSE
   IF nLen1 > N1
      nLen1 = N1
   ENDIF
ENDIF
   
if N1>nLen1
   LOCAL i,Nm,ary[nLen1]
   Nm=1
   FOR i=1 TO nLen1
       IF ASC(SUBSTR(cStr1,i,1))>126
          ary[i]=Nm
          Nm=Nm+1
       ELSE
          ary[i]=0
       ENDIF
   ENDFOR
            
   IF ASC(substr(cStr1,nLen1,1)) > 126
      IF ary(nLen1)>0 and MOD(ary(nLen1),2)=0
         cStr2=SUBSTR(cStr1,1,nLen1)
      ELSE
         cStr2=SUBSTR(cStr1,1,nLen1-1)
      ENDIF
   ELSE  
      cStr2=SUBSTR(cStr1,1,nLen1)

   ENDIF
ELSE
   cStr2 = cStr1   
ENDIF
RETURN cStr2
ENDFUNC
收到的鲜花
  • tlliqi2017-02-24 19:02 送鲜花  10朵   附言:谢谢
搜索更多相关主题的帖子: 字符串 登山 
2017-02-24 17:32
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
以下是引用吹水佬在2017-2-24 20:18:14的发言:

可否这样:先计数后截取,单字节字符计1,双字节字符计2。
如:
FUNCTION _CutStr(cStr,nLen)
    LOCAL nCount
    nCount = 0
    DO WHILE nCount
吹版,你知道的函数真多阿。你的代码够简洁的。。。
不过,我和你的,结果有点出入,当遇到中文时,我取的是比N-1,你的是N+1
不知道是N-1好还是N+1好

[此贴子已经被作者于2017-2-24 21:19编辑过]

2017-02-24 21:14
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
*优化1楼后
CLEAR
Str1 = "123456人发可个方和方经品他三方登1山泛水多福多寿辅导费对方01234567890"

? CutStr(str1,31,0)
? CutStr(str1,31,1)

FUNCTION CutStr(cStr1,nLen1,nAdd)
LOCAL N1,cStr2

*!* 强行将参数值转换为字符串,并去掉字符串右边的空格
cStr1 = RTRIM(TRANSFORM(cStr1))

*!* 长度参数错误或者大于字符串长度,取字符串最大长度
N1 = LEN(cStr1)
nLen1 = IIF(TYPE("nLen1") # "N",N1,IIF(nLen1>N1,N1,nLen1))

*!* 截取的最后一个字符是半个双字节时,是舍去还是保留
nAdd = IIF(TYPE("nAdd") # "N",0,IIF(nAdd = 1,1,0))

if N1 > nLen1
   LOCAL i,nCount
   nCount = 0
   *!* 计算字符是双字节还是单字节,是第1位还是第2位
   FOR i=1 TO nLen1
       IF ISLEADBYTE(SUBSTR(cStr1,i,1)) = .T. &&判断双字节时计数 +1
          nCount = nCount + 1
       ENDIF
   ENDFOR

   IF ISLEADBYTE(SUBSTR(cStr1,i,1)) = .T. &&判断是不是双字节
      IF MOD(nCount,2)=0 &&判断是否双字节的第2位
         cStr2=SUBSTR(cStr1,1,nLen1)
      ELSE
         cStr2=IIF(nAdd = 0,SUBSTR(cStr1,1,nLen1-1),SUBSTR(cStr1,1,nLen1+1))
      ENDIF
   ELSE  
      cStr2=SUBSTR(cStr1,1,nLen1)
   ENDIF
ELSE
   cStr2 = cStr1   
ENDIF

RETURN cStr2
ENDFUNC


[此贴子已经被作者于2017-2-24 23:49编辑过]

2017-02-24 23:02
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
以下是引用qingfameng在2017-2-24 23:27:44的发言:

截取‘混杂字符’的长型字串,个人认为没这么复杂(抱歉!只是个人意见!)。即:不需要作判断'单双字节',采用的是直接固定截取,清除,再截取方式。比较简单。在sql server 表中,从TEXT 字段内取出的文章,里面是什么样的字符都有,我就是这样分段的,现在也一直实际用着。(代码后续) ....
 
 
 
中文版的 sql server ,是用nvarchar来保存的,无论是取多少个,都不会有半个字符的,但在VFP中取,就会出现半个字符
2017-02-24 23:51
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
以下是引用kiff在2017-2-25 11:36:31的发言:

Str1 = "12345人发可个方和方经品他三方登山泛水多福多寿辅导费对方012345678901nLen1-1456789"
nLen1=32
?SUBSTRC(LEFT(str1,nLen1),1)
还可以这样的。
你的是遇到取的最后1位是双字节的第1位时,舍去。
4楼是遇到取的最后1位是双字节的第1位时,取多1位。

把你的和4楼的整合起来,就可以选择最后1为是舍去还是保留了。或者用7楼
整合后如下:
CLEAR


Str1 = "123456人发可个方和方经品他三方登山泛水多福多寿辅导费对方012345678901nLen1-1456789"
nLen1=31

? CutStr(str1,nLen1,0)
? CutStr(str1,nLen1,1)
? _CutStr(str1,nLen1,0)
? _CutStr(str1,nLen1,1)

*!* ======================================
*!* 先计算最后1位是双字节的第1位还是第2位
*!* 根据选择是舍弃还是保留最后1位的双字节
*!* ======================================
FUNCTION CutStr(cStr1,nLen1,nAdd)
LOCAL N1,cStr2

*!* 强行将参数值转换为字符串,并去掉字符串右边的空格
cStr1 = RTRIM(TRANSFORM(cStr1))

*!* 长度参数错误或者大于字符串长度,取字符串最大长度
N1 = LEN(cStr1)
nLen1 = IIF(TYPE("nLen1") # "N",N1,IIF(nLen1>N1,N1,nLen1))

*!* 截取的最后一个字符是半个双字节时,是舍去还是保留
nAdd = IIF(TYPE("nAdd") # "N",0,IIF(nAdd = 1,1,0))

if N1 > nLen1
   LOCAL i,nCount
   nCount = 0
   *!* 计算字符是双字节还是单字节,是第1位还是第2位
   FOR i=1 TO nLen1
       IF ISLEADBYTE(SUBSTR(cStr1,i,1)) = .T. &&判断双字节时计数 +1
          nCount = nCount + 1
       ENDIF
   ENDFOR

   IF ISLEADBYTE(SUBSTR(cStr1,i,1)) = .T. &&判断是不是双字节
      IF MOD(nCount,2)=0 &&判断是否双字节的第2位
         cStr2=SUBSTR(cStr1,1,nLen1)
      ELSE
         cStr2=IIF(nAdd = 0,SUBSTR(cStr1,1,nLen1-1),SUBSTR(cStr1,1,nLen1+1))
      ENDIF
   ELSE  
      cStr2=SUBSTR(cStr1,1,nLen1)
   ENDIF
ELSE
   cStr2 = cStr1   
ENDIF

RETURN cStr2
ENDFUNC

*!  ========================================================
*!* 利用4楼和10方法整合后,可以选择舍去还是保留最后1位双字节
*!  ========================================================
FUNCTION _CutStr(cStr1,nLen1,nAdd)
  LOCAL nCount,N1

  *!* 强行将参数值转换为字符串,并去掉字符串右边的空格
  cStr1 = RTRIM(TRANSFORM(cStr1))

  *!* 长度参数错误或者大于字符串长度,取字符串最大长度
  N1 = LEN(cStr1)
  nLen1 = IIF(TYPE("nLen1") # "N",N1,IIF(nLen1>N1,N1,nLen1))

  *!* 截取的最后一个字符是半个双字节时,是舍去还是保留
  nAdd = IIF(TYPE("nAdd") # "N",0,IIF(nAdd = 1,1,0))

  IF nAdd = 0
     RETURN SUBSTRC(LEFT(cStr1,nLen1),1)
  ELSE
     nCount = 0
     DO WHILE nCount < nLen1
        nCount = nCount + IIF(ISLEADBYTE(SUBSTR(cStr1,nCount+1,1)), 2, 1)
     ENDDO
     RETURN LEFT(cStr1,nCount)
  ENDIF
  
ENDFUNC

[此贴子已经被作者于2017-2-25 12:16编辑过]

2017-02-25 11:46
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
以下是引用吹水佬在2017-2-27 10:43:43的发言:

对于纯文本数据,就是由键盘正常编辑输入的字符(特殊输入的不算,如Ctrl+XXX或Alt+XXX等),这类纯文本数据还有规律可寻,比较好处理。对于一些字节流的数据(如二进制文件数据或网络数据),要在其中取出一段内容的文字显示而不出现“乱码”,除了逐字节分析,还有没有更简的方法?

吹版,Kiff 提到的,先用 substr()或者left()取,然后再用 substrc()取,他会把第1次取的,如果最后1位是乱码的去掉的。
不知道,你说的“对于一些字节流的数据(如二进制文件数据或网络数据)”能否适应这种方法,他不用循环,速度比“逐字节分析”快很多。
2017-02-27 12:42
mywisdom88
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:190
帖 子:3125
专家分:8340
注 册:2015-3-25
得分:0 
以下是引用qingfameng在2017-2-27 18:48:00的发言:

如果吹版能给出一篇有各种字符,也有乱码的文件,我测试一下自己搞的那段代码,看看是否可行? 代码是很早时候受kiff 版主的启发,而搞得。

也用是substr(left())这样的方式?
没想到,这个问题,认真讨论,还有这么多情况。
2017-02-28 08:58



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-474515-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.196063 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved