找回密码
 点一下
查看: 11782|回复: 24

string彻底研究V1.17。现在终于可以方便的按字符处理字符串了

[复制链接]
发表于 2006-4-3 22:54:43 | 显示全部楼层 |阅读模式
字符串函数其实有很多人做过,比如wc3jass.com,但是它们都没提供按字符处理字符串的功能,而且不够系统化
犹豫了半天,最后还是决定发上来


一楼:介绍及下载
二楼:函数一览
三楼:保留。现在用做2.0的规划
九楼:最核心的代码



名称:string彻底研究
作者:zyl910
版本:V1.1.7
日期:2006-4-3

文件说明
~~~~~~~~
ReadMe.txt:本说明文件
JassStr.j:所有代码
ByteChar.txt:详细说明了我是怎么选取特殊Unicode字符。
JassStr.w3x:测试字符串函数时所用地图
ShowUnicode.w3x:显示Unicode字符空间
LearnAbility.w3x:通过在聊天框输入技能代码来学习技能


缘由
~~~~
  由于WC3中字符串处理能力极其薄弱,所以根本没有详细的、系统的字符串处理资料。当需要写字符串处理代码时(如保存英雄信息的字符串密码),就只能硬着头皮写代码。
  我看过不少地图的代码,发现其中的字符串处理写得极其复杂、混乱、龌龊,简直看了想吐。
  为了改变这一现状,我决心研究string,编写正确的字符串处理代码。
  仅过了不断的努力,我终于解决了这个难题,构造出了Asc、Chr等基础字符串函数,现在终于可以方便的写字符串处理代码了。



string研究
~~~~~~~~~~
  WC3中有字符串这种数据类型,在WE中叫String,在Jass中叫string。其表现形式就是用双引号中括起的若干个字符,如:"中文ABC"。而且它与才C语言的字符串很相似,具有转义字符“\”:
    \\:0x5C。右斜线
    \":0x22。双引号
    \b:0x08。退格
    \t:0x09。Tab
    \n:0x0A。换行符
    \f:0x0C。换页
    \r:0x0D。回车符
    (注意,WC3只支持以上几种字符转义,并不支持C语言中“\0xFF”这样的字符转义)
  所以说,要想在字符串中书写“\”与“"”,得写成“\\”与“\"”。但如果是在触发器的“Set Variable(设置变量)”中填写字符串数据的话,WE会自动转换字符串数据,不需使用转义字符。

  还有一个很特殊的转义符??“%%”。
  如果需要在“自定义脚本区”书写“%”,得写成“%%”。当地图保存生成Jass代码时会将“%%”转换成“%”。
  如果是在触发器动作“自定义脚本”书写“%”的话,可以直接书写,不会自动转化。
  如果是在触发器中设置字符串变量的话,该转义符也无效。

  string运算符总共有以下三个(缺少的字符串比较大小运算符):
    +:字符串连接运算符(触发器中“Concatenate Strings”)。用于连接两个字符串,如"1" + "2"”这个表达式的结果是"12"
    ==:字符串相等比较运算符(触发器中“String Comparison”)。注意它是区分大小写的
    !=:字符串不相等比较运算符(触发器中“String Comparison”)。注意它是区分大小写的

  string处理函数总共有以下三个(暴雪也太吝啬了吧,尤其是StringCase函数根本用不上):
    StringLength:取得字符串的字节长度(触发器中“String Length”)。
    SubString:取得子字符串(触发器中的“Substring”)。
    StringCase:转换大小写。

  其中SubString函数是最使人迷惑的函数,让我们先看看它的函数原型:
native SubString takes string source, integer start, integer end returns string
  它的字符位置是从0开始的,返回的子字符串实际上 [start, end) 这个字节范围内的数据,并不包括end,如“SubString("123", 0, 2)”的返回值是“"12"”。
  而在触发器中则有些不同,按它说明字符位置似乎是从1开始的,且子串是 [start, end] 这个字节范围内的数据……哈哈,看了 SubStringBJ 的代码你就会明白的:
function SubStringBJ takes string source, integer start, integer end returns string
    return SubString(source, start-1, end)
endfunction

  其实以上内容并不是致命的,真正要命的问题是:string使用 UTF-8 编码来存储字符串数据的。
  在UTF-8编码中,一般汉字占3字节,而英文字母占1字节。注意StringLength、SubString均是以字节为单位的,不是字符。再加上缺少基本的字符串函数(如Asc、Chr),根本没办法按字符来处理字符串。
  比如说我想从某字符串中提取一个字节,但中英文字符所占字节不一样,而且没法判断谁是中文字符,这是个不可能完成的任务!

  如何解决这一问题呢?
  如果我们有0~255这些单字节的string样本的话,我们可以逐个逐个与当前单字节的string进行比较,以得到该单字节的string的编码数值,我们把这个功能叫做AscA函数。
  当有了AscA函数,我们可以根据UTF-8编码标准来编写Asc函数,得到当前字符及其Unicode编码。

  可怎么才能有0~255这些单字节的string样本呢?用Chr函数?!
  不不不??WC3中没有Chr函数,得我们自己编写Chr函数。
  注意string本身是UTF-8的,且在简体中文平台下,WE中允许我们输入中文,这一点似乎可以被利用。
  现在的简体中文平台用的是GBK编码,而GBK编码是基于GB13000-1993标准的。GB13000-1993参考了Unicode 3.0中的CJL部分,支持常用的简体汉字与繁体汉字,共收录2万多汉字,对应了很大一片Unicode编码空间。
  既然WE允许我们输入中文字符,且我们知道该字符经过UNT-8编码后是什么样子,这样我们可以选取一些关键的字符,使其尽可能多覆盖Unicode字符空间。由于我们能输入中文,所以中文绝对没问题(无论简繁),可其他语言(韩文日文)就难说了,但幸好我们一般不需要用。
  选取字符工作是极其的枯燥无味的,具体内容请看ByteChar.txt。
  (Unicode官方网站:www.unicode.org

  现在有了单字节的string样本,我们可以构造Asc、Chr函数了。
  由于Asc、Chr是基础函数,为了效率,我决定使用全局变量来存放数据。
  且在调用Asc、Chr函数前,必须调用InitByteData函数来做初始化操作。



使用说明
~~~~~~~~
一、在您的地图中新建这几个变量:
  ByteData:字符串数组
  ByteCode:整型数组
  AscLastChar:字符串
  AscLastCode:整型

二、打开触发编辑器,在左侧的树视图中点击第一个项目(你的地图名),注意右下角的“自定义脚本代码(S)”文本框,将JassStr.j中的代码复制过去(注意别复制globals)

三、在地图初始化的触发器中新建动作“Custom Script(自定义脚本)”,输入“call InitByteData()”

四、如何调用这些函数:
  A.新建动作“Custom Script(自定义脚本)”,然后书写单行Jass代码。
  B.选择一个触发器,执行菜单命令:编辑 --> 转换为自定义文本。
  C.在地图的自定义脚本区编写代码。




更新
~~~~
[2006-4-3] V1.1.7
试图使用更好的样本数据,但是都失败了。
但是此次尝试,让我发现了原样本数据所存在的Bug,修复之。


[2006-4-2] V1.1.6
1.试图解决浮动文字Bug,试过很多种方法都不行,放弃了。
2.LearnAbility.w3x


[2006-4-1] V1.1.5
ShowUnicode.w3x
发现重大Bug:若浮动文字显示了很多不同语言的字符,则文字图样会发生混乱


[2006-3-31] V1.1.4
重新设计了Asc函数,推荐使用这几个函数来按字符处理字符串:
CharNext:得到下一个字符的位置
CharPrev:得到前一个字符的位置
CharCur:得到当前字符的位置(自动跳过无效后续字节)


[2006-3-30] V1.1.3
InStrRev:反向查找子字符串
StrMidToEnd:取得从中间开始的子字符串
ScanByte:跳过某类字节数据
ScanByteRev:反向跳过某类扫描字节数据
EscapeColor:[WC3]颜色标记转义。使带有颜色的字符串能正常输出
UnescapeColor:[WC3]取消颜色标记转义
DeleteColor:[WC3]删除字符串中的颜色代码



[2006-3-29] V1.1.2
DecodeHex:将十六进制字符串转为整数
DecodeRadix:将任意进制字符串转为整数
Id2Str:[WC3]将代码转为字符串
Str2Id:[WC3]将字符串转为代码


[2006-3-28] V1.1.1
加入下列函数:
InStr:查找子字符串
StrReplace:替换子字符串
StrReverse:反转字符串
StrTrim:去掉首尾的某些字节


[2006-3-27] V1.1.0
加入下列函数:
StrLeft:取得左子字符串
StrRight:取得右子字符串
StrMid:取得中间的子字符串
StrDup:生成重复字符的字符串
HexN:整数转十六进制字符串(定长版)
ConvRadix:任意进制转换
ConvRadixN:任意进制转换(定长版)


[2006-3-26] V1.0
编写了下列函数:
Hex:整数转十六进制字符串
InitByteData:初始化字节数据数组
Chr:支持 Unicode 的 Chr 函数
AscA:得到某个字节的编码
Asc:得到首字符的 Unicode编码
AscEx:得到某字符的 Unicode编码(增强版)

[ 本帖最后由 zyl910 于 2006-4-4 11:43 编辑 ]

评分

参与人数 1威望 +2 收起 理由
疯人¢衰人 + 2

查看全部评分

 楼主| 发表于 2006-4-3 22:56:14 | 显示全部楼层

函数一览

函数一览
~~~~~~~~

// #######################################################
// ## String Function ####################################
// #######################################################
// [WC3]开头的表示是魔兽3专用函数,与魔兽相关设定挂钩
// 其他的表示是通用的字符串函数

// ## String Function: Byte ##############################
// 字节级函数:能只靠 StringLength、SubString 就能实现的函数
//

// 取得左子字符串
function StrLeft takes string s, integer iLength returns string

// 取得右子字符串
function StrRight takes string s, integer iLength returns string

// 取得中间的子字符串
function StrMid takes string s, integer iStart, integer iLength returns string

// 取得从中间开始的子字符串
function StrMidToEnd takes string s, integer iStart returns string

// 查找子字符串
function InStr takes string sSrc, string sFind, integer iStart returns integer

// 反向查找子字符串
function InStrRev takes string sSrc, string sFind, integer iStart returns integer

// 替换子字符串
function StrReplace takes string sSrc, string sFind, string sReplace, integer iStart, integer iCntRepl returns string

// 跳过某种字节数据
function ScanByte takes string sSrc, string byMatchs, integer iStart returns integer

// 反向跳过某种字节数据
function ScanByteRev takes string sSrc, string byMatchs, integer iStart returns integer

// 去掉首尾的某些字节
function StrTrim takes string sSrc, string byTrims, boolean bTrimStart, boolean bTrimEnd returns string

// 生成重复字符的字符串
function StrDup takes string ch, integer iCount returns string

// 整数转十六进制字符串
function Hex takes integer v returns string

// 整数转十六进制字符串(定长版)
function HexN takes integer v, integer iCount returns string

// 将十六进制字符串转为整数
function DecodeHex takes string s returns integer

// 任意进制转换
function ConvRadix takes integer v, integer iRadix returns string

// 任意进制转换(定长版)
function ConvRadixN takes integer v, integer iRadix, integer iCount returns string

// 将任意进制字符串转为整数
function DecodeRadix takes string s, integer iRadix returns integer

// [WC3]颜色标记转义。使带有颜色的字符串能正常输出
function EscapeColor takes string s returns string

// [WC3]取消颜色标记转义
function UnescapeColor takes string s returns string

// [WC3]删除字符串中的颜色代码
function DeleteColor takes string s returns string




// ## String Function: Unicode #############################
// Unicode基础函数库,可用来实现复杂函数
//

// 初始化字节数据数组。必须在调用Asc、Chr函数之前调用此函数
function InitByteData takes nothing returns nothing

// 支持 Unicode 的 Chr 函数
function Chr takes integer u returns string

// 得到某个字节的编码
function AscA takes string s, integer iStart returns integer

// 得到下一个字符的位置
function CharNext takes string s, integer iStart returns integer

// 得到前一个字符的位置
function CharPrev takes string s, integer iStart returns integer

// 得到当前字符的位置(自动跳过无效后续字节)
function CharCur takes string s, integer iStart returns integer

// 得到首字符的 Unicode编码
function Asc takes string s returns integer



// ## String Function: Char ##############################
// 字符级函数:使用了Unicode基础函数库的函数
//

// 反转字符串
function StrReverse takes string s returns string

// [WC3]将 ID 转为字符串
function Id2Str takes integer v returns string

// [WC3]将字符串转为代码
function Str2Id takes string sSrc returns integer
回复

使用道具 举报

 楼主| 发表于 2006-4-3 22:57:53 | 显示全部楼层

保留

大家看看我的2.0计划怎么样,有没有需要补充的地方




V2.0前景

去wc3jass.com搜刮了一下函数,开始计划2.0版。



决定加入的
~~~~~~~~~~

[Color Functions]
利用integer来存放颜色。格式:0xAARRGGBB

RGB
RGBA
RGBT
HSV:
GetRValue
GetGValue
GetBValue
GetAValue
GetTValue
SetRValue
SetGValue
SetBValue
SetAValue
SetTValue
GetPlayerColorRGB:取得玩家颜色
ColorText:生成彩色文本
GradientText:生成渐变文本
HighlightText:高亮子字符串


http://www.wc3jass.com/viewtopic.php?t=80
function CreateColorInteger takes integer red, integer green, integer blue, integer alpha returns integer
function ColorIntegerGetRed takes integer i returns integer
function ColorIntegerGetGreen takes integer i returns integer
function ColorIntegerGetBlue takes integer i returns integer
function ColorIntegerGetAlpha takes integer i returns integer

http://www.wc3jass.com/viewtopic.php?t=60
function GetPlayerColorCode takes player whichPlayer returns string

http://www.wc3jass.com/viewtopic.php?t=74
function TeamColor2RGB takes playercolor col returns string

http://www.wc3jass.com/viewtopic.php?t=134
function Degrade takes string Chaine, integer DRed, integer DGreen, integer DBlue, integer FRed, integer FGreen, integer FBlue returns string

http://www.wc3jass.com/viewtopic.php?t=90
function StringColorCrossFade takes string s, integer c1, integer c2, integer steps returns string



[Hotkey Functions]
Str2Hotkey:将字符转为热键
HotKey2Str:将热键转为字符
HighlightHotkey:将热键高亮

http://www.wc3jass.com/viewtopic.php?t=245
function Char2AsciiKeyValue takes string i returns integer

http://www.wc3jass.com/viewtopic.php?t=91
function HighlightHotkey takes string whichString, integer hotkey, string color returns string

http://www.wc3jass.com/viewtopic.php?t=246
function InsertHotkey takes string tip, string hotkey returns string


[Split Functions]
字符串拆分函数:
GetSplitItem:返回SplitItems中的数据
SplitJoin:合并字符串
SplitStr:拆分字符串。由于Jass中存在数组长度限制,函数返回值是已处理数据的字节长度
SplitChar:按字符拆分字符串。由于Jass中存在数组长度限制,函数返回值是已处理数据的字节长度
SplitSplit:按SplitItems拆分字符串。由于Jass中存在数组长度限制,函数返回值是已处理数据的字节长度
SplitInStr
SplitInStrRev
SplitReplace
SplitScan
SplitTrim

全局变量:
SplitItems:StrSplit的拆分结果
SplitCount:StrSplit拆分的总项目数


http://www.wc3jass.com/viewtopic.php?t=172
function ComputeStringFragments takes string s, string cutPoints returns integer

http://www.wc3jass.com/viewtopic.php?t=149
function GetDividedStringByIndex takes string S, string divider, integer index returns string

http://www.wc3jass.com/viewtopic.php?t=28
function StringFragment takes string s, integer sectionNum, string cutPoints returns string







考虑中的
~~~~~~~~
觉得这些函数用处不大,典型的鸡肋:食之无味,弃之可惜


取得已存在的字符串
http://www.wc3jass.com/viewtopic.php?t=50
function GetExternalString takes integer index returns string


随机混洗字符串中的字符顺序
http://www.wc3jass.com/viewtopic.php?t=2352
function GetRandomLetterOrder takes string wordString returns string


整数转罗马数字
http://www.wc3jass.com/viewtopic.php?t=107
function I2Roman takes integer n returns string


右对齐字符串
http://www.wc3jass.com/viewtopic.php?t=205
function rPad takes string input, string buffer, integer sz returns string


转为定长的字符串,超过长度则显示省略号
http://www.wc3jass.com/viewtopic.php?t=103
function StringAbbreviate takes string whichString, integer cutoff returns string


改变字符串中的内容
http://www.wc3jass.com/viewtopic.php?t=155
function StringChangeSubString takes string source, integer start, integer end, string replace returns string


不区分大小写的查找子字符串函数。注意整个31位unicode字符空间(20亿)中,只有少量西方语言有大小写概念,且Jass中的StringCase只对英文字符有用
http://www.wc3jass.com/viewtopic.php?t=33
function StringIFind takes string find, string subject, integer offset returns integer


判断是不是十六进制字符串的函数
http://www.wc3jass.com/viewtopic.php?t=144
function StringIsHexadecimal takes string source returns boolean


移动子字符串
http://www.wc3jass.com/viewtopic.php?t=148
function StringMoveSubString takes string source, integer start, integer end, integer move returns string


删除子字符串
http://www.wc3jass.com/viewtopic.php?t=143
function StringRemoveSubString takes string source, integer start, integer end returns string


根据条件返回不同的字符串
http://www.wc3jass.com/viewtopic.php?t=115
function StringTertiaryOp takes boolean condition, string s1, string s2 returns string




坚决不要的
~~~~~~~~~~
这些函数不适合在中文环境下使用


生成随机的单词
http://www.wc3jass.com/viewtopic.php?t=2381
function GetRandomConsonant takes nothing returns string
function GetRandomVowel takes nothing returns string
function GetRandomWord takes integer minl, integer maxl returns string


生成(英文)姓名
http://www.wc3jass.com/viewtopic.php?t=2382
function MakeFirstCapital takes string s returns string
function GetRandomPlayerName takes nothing returns string


按Word来拆分字符串
http://www.wc3jass.com/viewtopic.php?t=109
function Parser takes string ChatMsg, integer Word returns string


生成随机的(英文)字符串
http://www.wc3jass.com/viewtopic.php?t=204
function randomString takes integer min, integer max returns string




JassStr中已实现的
~~~~~~~~~~~~~~~~~

http://www.wc3jass.com/viewtopic.php?t=87
function AsciiCharToInteger takes string char returns integer
用:Asc。且我的函数是字符级的


http://www.wc3jass.com/viewtopic.php?t=88
function AsciiIntegerToChar takes integer i returns string
用:Chr。且我的函数是字符级的


http://www.wc3jass.com/viewtopic.php?t=137
function MidString takes string source, integer start, integer length returns string
用:StrMid


http://www.wc3jass.com/viewtopic.php?t=30
function StringFind takes string find, string subject, integer offset returns integer
用:InStr


http://www.wc3jass.com/viewtopic.php?t=40
function StringRepeat takes string whichString, integer times returns string
用:StrDup


http://www.wc3jass.com/viewtopic.php?t=31
function StringReplace takes string find, string replace, string subject returns string
用:StrReplace


http://www.wc3jass.com/viewtopic.php?t=29
function StringReverse takes string s returns string
用:StrReverse。且我的函数是字符级的


http://www.wc3jass.com/viewtopic.php?t=3
function StringTrimLeft takes string s returns string
http://www.wc3jass.com/viewtopic.php?t=4
function StringTrimRight takes string s returns string
http://www.wc3jass.com/viewtopic.php?t=5
function StringTrim takes string s returns string
用:StrTrim
回复

使用道具 举报

发表于 2006-4-4 00:17:19 | 显示全部楼层
强烈的支持!名副其实够彻底 ~

[ 本帖最后由 illlusion 于 2006-4-4 03:29 编辑 ]
回复

使用道具 举报

发表于 2006-4-4 00:36:40 | 显示全部楼层
手册将收录你的大作!

这年头作基础研究的已经很少了。好样的!
回复

使用道具 举报

发表于 2006-4-4 01:17:21 | 显示全部楼层
不顶对不起自己。不顶对不起GA。不顶对不起楼主。
顶。
另外。还没得看代码。明天睡觉起来再说。。。
从刚刚的另一帖说明天睡觉起来再说到现在已经半个小时了。嗯嗯。真的要睡觉了。
再次感谢楼主。嗯嗯。
回复

使用道具 举报

发表于 2006-4-4 07:58:56 | 显示全部楼层
MB~~~
如此费心费力 着实不易
凑字凑字~~~
回复

使用道具 举报

发表于 2006-4-4 10:42:36 | 显示全部楼层
完全看不懂~~但还是要膜拜膜拜膜拜`~5555
回复

使用道具 举报

 楼主| 发表于 2006-4-4 11:41:00 | 显示全部楼层
附件: [JassStrV1_1_7(20060403)] JassStrV1_1_7(20060403).rar (2006-4-3 22:54, 117.33 K)
该附件被下载次数 0


?!

主要是因为代码太长,论坛有字数限制,所以没贴代码。

JassStr.j:31,084 字节

算了
将最核心的代码贴上来:
[jass]
// ## String Function: Unicode #############################
// Unicode基础函数库,可用来实现复杂函数
//

// [private]初始化字节数据数组 -- 字符数据样本
function InitByteData_Sample takes nothing returns string
    return \"........\\b\\t\\n.\\f\\r.................. !\\\"#$%%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~一丁?七???万丈三上下丌不与?丐丑?专且丕世?丘丙业丛东丝丞???丢?两严?丧丨?个丫丬中??丰?串?临?丶?丸丹为主?丽举丿1212±÷āō12ǔ12?12?1212ΩπЖю1212121212121212121212121212123123※々一倍怀火耀退123123123123123?1234123412341234123412341234123412345123451234512345123456123456..\"
endfunction

// [private]初始化字节数据数组 -- 填充
function InitByteData_Fill takes string sSample, integer iStart, integer iIndex, integer iSize, integer iBytePos, string sDefChar returns nothing
    local integer cbChar = StringLength(sDefChar)
    local integer iMaxIndex = iStart + iSize
    loop
        exitwhen iIndex >= iMaxIndex
        if SubString(sSample, iStart, iStart + cbChar) != sDefChar then
            set udg_ByteData[iIndex] = SubString(sSample, iStart + iBytePos, iStart + iBytePos + 1)
        else
            set udg_ByteData[iIndex] = \"\"
        endif
        set iStart = iStart + cbChar
        set iIndex = iIndex + 1
    endloop
endfunction

// 初始化字节数据数组。必须在调用Asc、Chr函数之前调用此函数
function InitByteData takes nothing returns nothing
    local string sSample = InitByteData_Sample()
    local string sDefChar
    local integer iStart
    local integer iSize
    local integer Idx
    local integer I
   
    // Check
    if StringLength(udg_ByteData[0x20]) > 0 then
        return
    endif
   
    // Clear Array
    set I = 0
    loop
        exitwhen I > 0xFF
        //
        set udg_ByteData[I] = \"\"
        set udg_ByteCode[I] = 0
        //
        set I = I + 1
    endloop
   
    // Start
    set iStart = 0
    set Idx = 0
   
    // ASCII control
    set sDefChar = \".\"
    set iSize = 0x20
    call InitByteData_Fill(sSample, iStart, Idx, iSize, 0, sDefChar)
    set Idx = Idx + iSize
    set iStart = iStart + StringLength(sDefChar) * iSize
   
    // ASCII Text
    set sDefChar = \"\\b\"
    set iSize = 0x60
    call InitByteData_Fill(sSample, iStart, Idx, iSize, 0, sDefChar)
    set Idx = Idx + iSize
    set iStart = iStart + StringLength(sDefChar) * iSize
   
    // 0x80 ~ 0xBF
    set sDefChar = \"123\"
    set iSize = 0x40
    call InitByteData_Fill(sSample, iStart, Idx, iSize, 2, sDefChar)
    set Idx = Idx + iSize
    set iStart = iStart + StringLength(sDefChar) * iSize
   
    // 0xC0 ~ 0xFD
    set iSize = 0x20
    set I = 2
    loop
        exitwhen I > 6
        //
        set sDefChar = SubString(\"123456\", 0, I)
        call InitByteData_Fill(sSample, iStart, Idx, iSize, 0, sDefChar)
        set Idx = Idx + iSize
        set iStart = iStart + StringLength(sDefChar) * iSize
        //
        set iSize = iSize / 2
        set I = I + 1
    endloop
   
    // 0xFE ~ 0xFF
    set sDefChar = \".\"
    set iSize = 2
    call InitByteData_Fill(sSample, iStart, 0xFE, iSize, 0, sDefChar)
   
    // Fill udg_ByteCode[]
    set sDefChar = udg_ByteData[0]
    set iStart = 0
    set I = 1
    loop
        exitwhen I > 0xFF
        //
        if StringLength(udg_ByteData[I]) > 0 then
            set sDefChar = udg_ByteData[I]
            set iStart = I
        else
            set udg_ByteData[I] = sDefChar
        endif
        set udg_ByteCode[I] = iStart
        //
        set I = I + 1
    endloop
   
endfunction


// 支持 Unicode 的 Chr 函数
function Chr takes integer u returns string
    local string sRet = \"\"
    local integer iMaxCode
    local integer tmp
   
    // Check
    if u < 0 then
        return \"\"
    endif
   
    // ASCII
    if u <= 0x7F then
        if udg_ByteCode == u then
            return udg_ByteData
        else
            return \"?\"
        endif
    endif
   
    // Main
    set iMaxCode = 0x40
    loop
        // 后续字节
        set tmp = u / 0x40 // 6 bit
        set sRet = udg_ByteData[0x80 + (u - tmp * 0x40)] + sRet
        set u = tmp
        set iMaxCode = iMaxCode / 2
        
        // 首字节
        if u < iMaxCode then
            set u = 0x100 - iMaxCode * 2 + u
            if u != udg_ByteCode then
                return \"?\"
            endif
            set sRet = udg_ByteData + sRet
            exitwhen true
        endif
        
    endloop
   
    return sRet
endfunction


// [private]得到某个字节的编码
//Return: 该字节的编码。为 -1 表示无法识别
function AscA_Do takes string ch, integer iMin, integer iMax returns integer
    local integer I = iMin
    local integer byOld = -1
   
    // 查找字节的编码
    loop
        exitwhen I > iMax
        //
        if byOld != udg_ByteCode[I] then // 不检查没有编码的元素
            if ch == udg_ByteData[I] then
                // 找到了
                return udg_ByteCode[I]
            endif
            set byOld = udg_ByteCode[I]
        endif
        //
        set I = I + 1
    endloop
   
    return -1
endfunction

// 得到某个字节的编码
//Return: 该字节的编码。为 -1 表示无法识别
function AscA takes string s, integer iStart returns integer
    local string ch // 当前字节
    local integer I
   
    // 判断范围
    set I = StringLength(s)
    if (iStart < 0) and (iStart >= I) then
        return -1
    endif
    set ch = SubString(s, iStart, iStart + 1)
   
    return AscA_Do(ch, 0, 0xFF)
endfunction


// 得到下一个字符的位置
function CharNext takes string s, integer iStart returns integer
    local integer cbSrc = StringLength(s)
    local string  ch
    local integer byFirst
    local integer byCur
    local integer byMask
    local integer iCount
    local integer I
   
    // Begin
    set udg_AscLastChar = \"\"
    set udg_AscLastCode = -1
   
    // Check String Length
    if iStart < 0 then
        return 0
    elseif iStart >= cbSrc then
        return -1
    endif
   
    // Get First Byte
    set udg_AscLastChar = SubString(s, iStart, iStart + 1)
    set byFirst = AscA_Do(udg_AscLastChar, 0, 0xFF)
    if (0 <= byFirst) and (byFirst <= 0xFF) then // 能识别的字符
        // Get Char Length
        set iCount = 0
        set byCur = byFirst
        if byCur < 0xFE then
            // 用加减模拟位运算:从左到右做位扫描,碰到为0的位便中止
            set byMask = 0x80
            loop
                exitwhen byCur < byMask
                set byCur = byCur - byMask
                set iCount = iCount + 1
                set byMask = byMask / 2
            endloop
        else
            set iCount = 1
        endif
        
        // Get Char
        if iCount == 0 then // ASCII
            set udg_AscLastCode = byFirst
        elseif iCount == 1 then // 无效的后续字节,或0xFE、0xFF
            set udg_AscLastCode = -byFirst
        elseif iCount <= 6 then // UTF-8编码字符
            if (iStart + iCount) <= cbSrc then
                set udg_AscLastCode = byCur // 看明白前面那个循环怎么结束了吗
                // For[1, iCount)
                set I = 1
                loop
                    exitwhen I >= iCount
                    //
                    set iStart = iStart + 1
                    set ch = SubString(s, iStart, iStart + 1)
                    set byCur = AscA_Do(ch, 0x80, 0xBF)
                    if (0x80 <= byCur) and (byCur <= 0xBF) then //正确的后续字节
                        set udg_AscLastChar = udg_AscLastChar + ch
                        set udg_AscLastCode = udg_AscLastCode * 0x40 + (byCur - 0x80)
                    else // 不是正确的后续字节
                        set iStart = iStart - 1
                        set udg_AscLastCode = -byFirst
                        exitwhen true
                    endif
                    //
                    set I = I + 1
                endloop
            else // 字符串长度不够,无法识别
                set udg_AscLastChar = SubString(s, iStart, cbSrc)
                set udg_AscLastCode = -byFirst
            endif
        endif
    else
        set udg_AscLastCode = -2
    endif
    set iStart = iStart + 1
   
    // 对于不能识别的字符,尝试串接后面的后续字节
    if udg_AscLastCode < 0 then
        loop
            exitwhen iStart >= cbSrc
            //
            set ch = SubString(s, iStart, iStart + 1)
            set byCur = AscA_Do(ch, 0x80, 0xBF)
            exitwhen byCur < 0
            set udg_AscLastChar = udg_AscLastChar + ch
            //
            set iStart = iStart + 1
        endloop
    endif
   
    return iStart
endfunction

// 得到前一个字符的位置
function CharPrev takes string s, integer iStart returns integer
    local integer cbSrc = StringLength(s)
    local string  ch
    local integer byCur
    local integer byOld = 0
    local integer byMask
    local integer iCount
    local integer iCntByte
    local integer iSALn
   
    // Begin
    set udg_AscLastChar = \"\"
    set udg_AscLastCode = -1
   
    // Check iStart
    if iStart <= 0 then
        return -1
    elseif iStart >= cbSrc then
        set iStart = cbSrc
    endif
   
    // Main
    set udg_AscLastCode = 0
    set iSALn = 1
    set iCntByte = 0
    loop
        set iStart = iStart - 1
        if iStart < 0 then // 突然结束,无法识别
            set udg_AscLastCode = -2
            set iStart = 0
            exitwhen true
        endif
        //
        set ch = SubString(s, iStart, iStart + 1)
        if 0 == iCntByte then
            set byCur = AscA_Do(ch, 0, 0xFF)
        else
            set byCur = AscA_Do(ch, 0x80, 0xFF)
        endif
        if (0 <= byCur) and (byCur <= 0x7F) then // ASCII
            if 0 == iCntByte then
                set udg_AscLastChar = ch
                set udg_AscLastCode = byCur
            else // ASCII 后不能接后续字节
                set udg_AscLastCode = - byOld
                set iStart = iStart + 1
            endif
            exitwhen true
        else
            set udg_AscLastChar = ch + udg_AscLastChar
            set iCntByte = iCntByte + 1
            if (byCur < 0) or (byCur > 0xFF) then // 无法识别
                set udg_AscLastCode = -2
                exitwhen true
            elseif byCur <= 0xBF then // 后续字节
                if iCntByte <= 5 then
                    set udg_AscLastCode = iSALn * (byCur - 0x80) + udg_AscLastCode
                    set iSALn = iSALn * 0x40
                else
                    set udg_AscLastCode = - byCur
                    exitwhen true
                endif
            elseif byCur <= 0xFD then // 首字节
                // Get Char Length
                set iCount = 2
                set byOld = byCur - 0xC0
                set byMask = 0x20
                loop
                    exitwhen byOld < byMask
                    set byOld = byOld - byMask
                    set iCount = iCount + 1
                    set byMask = byMask / 2
                endloop
                // Check Length
                if iCntByte == iCount then
                    set udg_AscLastCode = iSALn * byOld + udg_AscLastCode
                else
                    set udg_AscLastCode = - byCur
                endif
                exitwhen true
            else // 0xFE, 0xFF
                set udg_AscLastCode = -byCur
                exitwhen true
            endif
        endif
        set byOld = byCur
    endloop
   
    return iStart
endfunction

// 得到当前字符的位置(自动跳过无效后续字节)
function CharCur takes string s, integer iStart returns integer
    local integer iRet = iStart
    loop
        set iRet = CharNext(s, iRet)
        exitwhen (udg_AscLastCode <= -192) or (udg_AscLastCode > -128)
    endloop
    return iRet
endfunction

// 得到首字符的 Unicode编码
//Return: 当前字符的Unicode编码。超过字符串范围返回-1,无法识别的字符返回-2,无效字符则返回负首字节
function Asc takes string s returns integer
    call CharNext(s, 0)
    return udg_AscLastCode
endfunction
[/jass]

[ 本帖最后由 zyl910 于 2006-4-4 11:46 编辑 ]
回复

使用道具 举报

发表于 2006-4-4 12:19:53 | 显示全部楼层
终于出来老...
研究先....

要不顺便加入支持正则表达式的功能...:lol

[ 本帖最后由 白银の游戏王 于 2006-4-4 12:33 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2006-4-4 12:54:38 | 显示全部楼层
原帖由 白银の游戏王 于 2006-4-4 12:19 发表
终于出来老...
研究先....

要不顺便加入支持正则表达式的功能...:lol


正则表达式?



曾见过一个Delphi版的,先将正则表达式编译成有限自动机,再用编译好的有限自动机来解析字符串
总代码量5000行

而且Jass变量功能薄弱
如果Jass支持面向对象的话,我还会考虑一下的
回复

使用道具 举报

发表于 2006-4-4 14:24:57 | 显示全部楼层
呃。忽然发现那唯一的一次是我下的。
难道是楼主更新过了咩。。
研究中。有很多不明白D。。
回复

使用道具 举报

发表于 2006-4-9 10:51:18 | 显示全部楼层
强贴留名拜过~
有时间再来分析研究
回复

使用道具 举报

发表于 2006-4-15 15:41:30 | 显示全部楼层
完全看不懂~~但还是要膜拜膜拜膜拜`~5555
回复

使用道具 举报

发表于 2006-5-16 01:42:42 | 显示全部楼层
我相信!我花一辈子的时间还未必看得懂这些东西 痛苦啊 嚎叫吧...
PS:睡觉去咯GA晚安

[ 本帖最后由 Toad 于 2006-5-16 01:45 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2006-5-16 13:04:34 | 显示全部楼层
原帖由 Toad 于 2006-5-16 01:42 发表
我相信!我花一辈子的时间还未必看得懂这些东西 痛苦啊 嚎叫吧...
PS:睡觉去咯GA晚安


就是你相信你学不会你才会这样

从小学时我就坚信宇宙是可理解的,所以每隔一段时间都翻出爱因斯坦的《相对论》专著看一遍。虽然到了现在也无法完全看懂,但是每看一遍都有收获,特别是能提高思维能力
(所以前几年看《黑衣人》中主角说“那个拿着高等物理书的小孩是外星人”时,我无语)

等级是练出来!
如果你觉得哪个领域是不可理解的,那是因为你没阅读那方面的专业书籍

该代码涉及的技术是:《数据结构》中的“串”处理、Unicode文本编码UTF-8

[ 本帖最后由 zyl910 于 2006-5-16 17:40 编辑 ]
回复

使用道具 举报

发表于 2006-5-16 13:12:08 | 显示全部楼层
感谢楼上的教诲!
回复

使用道具 举报

发表于 2006-5-28 15:21:26 | 显示全部楼层
看到楼主的研究,我又有了动力。^_^
回复

使用道具 举报

发表于 2006-5-28 16:55:03 | 显示全部楼层
理解相对论有两种方式:
一种是爱因斯坦的方法 --- 可深切感受到整个理论是如何在历史中一步步发展建立起来的 但这种方式需要很丰富的物理背景 不然很容易概念逻辑混乱

一种是几何的方法     --- 足以让你感受到宇宙是如此的和谐 物理定律是如何的优美简明 但这种方式需要很强的物理直觉和一定的数学

现在我国对相对论基础理论的教育几乎为0 都是让你背几个公式会算题就算了事了(因为其实大部分教授也不懂) 但会用公式算题和理解公式的意义可是两回事 所以下次你要是听到谁说“相对论阿,懂的懂得,大学里学过呢”的话 基本上可以无视。。。。
所以~~自学才是王道...
支持zyl 敬佩zyl的精神 现在这样的人已经快绝迹了:lol
回复

使用道具 举报

发表于 2009-9-4 10:59:50 | 显示全部楼层
甘愿接受挖坟的处罚,只求

附件: [JassStrV1_1_7(20060403)] JassStrV1_1_7(20060403).rar (2006-4-3 22:54, 117.33 K)
该附件被下载次数 0

这个附件,!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-4-20 11:29 , Processed in 0.085281 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表