//string 字符串 namespace builtin; self.string = global.string; namespace string{ gfind = function(str,p,f){ if(!f) f = 0; var r = function(b,e,...){ if( b ) f = ( e > b ) ? e : b ; return b,e,...; }; return function(){ return r( find(str,p,f+1) ); } }; matches = function(s,...){ return ..table.array(gmatch(s,...) ); }; splitEx = function(s,p,l,f){ if(!#s) return []; p = p:"<\r*\n>|\r"; var a = 0; if(p[1]=='^'#){ a = 1;p = right(p,-2); } if(p[#p]=='$'#){ a = a + 2; p = left(p,-2); } if( a==3) a=2#100; var m1; var e1 = 0; var ret = [] var push = ..table.push; var next = gfind(s,p,f); var l2 = 1; do{ var b2,e2,m2; if(!l || l>l2) b2,e2,m2 = next(); if(b2) b2--; var r = sub(s,e1+1,b2); if(a) { if( m2 && a==2#100){ push(ret,r,m2);l2++;} elseif( m1 && a&1) push(ret,m1 ++ r); elseif( m2 && a&2) push(ret,r ++ m2); else push(ret,r); } else { push(ret,r); } e1 = e2; m1 = m2; l2++; }while(e1) return ret; }; table = function(s,d,p,im){ var r = {} for( a in lines(s,p,d:"[ \t]*[\:=][ \t]*",2) ){ if(#a!=2) continue; var c,k,v = a[1][1],a[1],a[2]; if( c!='#'# && c!=';'#){ if(im)v=match(v,"([^;#]+!\s)<\s+[;#]>?"); if(k[#k]!=']'# ) r[k] = v; else ..table.set(k,v,r); } } return r; }; lines = function(s,p,separator,limit){ if(!#s) return function(){}; p = p:"<\r*\n>|\r"; var a = 0; if(p[1]=='^'#){ a = 1;p = right(p,-2); } if(p[#p]=='$'#){ a = a + 2; p = left(p,-2); } if(a==3) a = 2#100; var m1,m2; var e1 = 0; var b2,e2; var next = gfind(s,p); return function(){ if( e1 === null ) return; if( a==2#100 && m1){ m1 = null; if(separator)return splitEx(m2,separator,limit),true; return m2,true; } b2,e2,m2 = next(); if(b2) b2--; var r = sub(s,e1+1,b2); if(a ) { if( m1 && a&1) r = m1 ++ r; elseif( m2 && a&2) r = r ++ m2; } e1 = e2; m1 = m2; if(separator) r = splitEx(r,separator,limit); return r; } }; each = function(s,p,line){ if(!p) error("请指定参数@2",2) var t,i = splitEx(s,line),0; return function(){ var m; while(!#m){ i = i + 1; if(!t[i]) return; m = { match(t[i],p) }; } return ..table.unpack(m); } }; eachChar = lambda (s) gmatch(s,":|."); cmpMatch = function(a,b){ var t = type(a); return ( (t==type(b)) && (t == "string" ) && ( ( cmp( a,b) == 0 ) || ( match( lower(a) ,lower(b) ) ) ) ) }; concatUtf16 = function(...){ var args = {...}; for i,v in ..table.eachArgs(args){ args[i] = toUtf16(v); } return sliceUtf16( (join(args))); } isUtf8 = function(s){ if( !#s ) return; var u = getUtf(s); if( u & 8 ) return true; if( u & 1 ) return; if( u & 16 ) return; var m = match(s,'[\x80-\xFF]+') //'€'# if( !#m ) return; if( !len(s) ) return false; if( #m > 50 ) return true; if( fromUtf16(toUtf16(m,65001) ,65001) != m ) return false; return true; } self.loadcode = function(c,...){ var f,e = loadcode(c,"=(string.loadcode)"); if(!f) return null,e; var p = ..print; var t = {}; ..print = function(s,...){ if(s!==null) ..table.push(t,tostring(s)); if(...===null) return; return ..print(...); } var r,e = callex(,f,...,...); ..print = p; if(!r) return null,e; return join(t); }; search = function(f,s,p,...){ var r; if( type(f) === "table" ){ r = f; f = function(m,...) ..table.push(r,... ? {m;...} : m); } if( type( p ) === "function" ){ if(!s) return r; var m = p(s); if(!m) return r; elseif( type(m) == "string") s = m; if(...) search(f,s,...); else f(s); return r; } if(!...) replace(s,p,f); else { if(p[1]=='^'#) { m = match(s,p); if(m) search(f,m,...); return r; } for m in gmatch(s,p) search(f,m,...); } return r; }; map = function(s,p,f){ var r,m = [] if( type(p) == "string" ) p = {p}; elseif(!p ) { p = {"[-\d]+"}; if(!f) f = tonumber; } if(!f) f = lambda(s,...) ... ? {s;...} : s; if(#p){ search(function(...){ m = f(...); if( m!==null ) ..table.push(r,m); },s,..table.unpack(p) ); } else { for(k,v in p) r[k] = map(s,v,f)[1]; } return r; }; repline = function(s,p,r,c){ return ( replace(s,"\N+",lambda(line) replace(line,p,r,c) ) ); }; replaceUnmatched = function(s,p,rep,keep,...){ var a = 0; var r = {} if(keep) keep = replace(keep,"\\(\d)",lambda(d) "\"+(d+1)); for part,sep in lines(s,"^("+keep+")$") { if(sep) ..table.push(r,part) else{ var n,c; if(...) n,c = replaceUnmatched(part,p,rep, ...); else n,c = replace(part,p,rep); ..table.push(r,n); a+=c; } } return join(r),a; }; reduceReplace = function(s,m,p,...){ if(!...) return replace(s,m,p); var args = {p,...} return replace(s,m,function(nextstr){ return reduceReplace(nextstr,..table.unpackArgs(args)); }) }; self.reduce = function(s,p,...){ if( type(p) !="table" ) p = {p;...}; return reduce(p, lambda(s,p) s ? match(s,p),s); }; crlf = function(s,c,n){ if(s!==null) { c = c ?(c===true?'\n':c):'\r\n'; s = replace(tostring(s),"<\r\n>|\n|\r",c); if(n!==null) s = replace(s,"<"+c+">\s*<"+c+">",repeat(n+1,c)); return s; } }; removeBom = function(s){ if(!s) return s; var c1 = s[1]; if(c1 == 0xEF && s[2] == 0xBB && s[3] == 0xBF) return right(s,-4); elseif(c1 == 0xFF && s[2] == 0xFE) return fromto(right(s,-3),1200,65001); elseif(c1 == 0xFE && s[2] == 0xFF) return fromto(right(s,-3),1201,65001); return s; }; setenv = ::Kernel32.api( "SetEnvironmentVariable", "INT(ustring name,ustring v)"); var getEnvironmentVariable = ::Kernel32.api( "GetEnvironmentVariable", "INT(str name,str &v,INT size)"); getenv = function(name){ var len,val = getEnvironmentVariable(name,256,256); if(len > 256) len,val = getEnvironmentVariable(name, len,len); if(len) return val; } expand = function(s,p,r){ var c; if(!p){p,r="\%([^%]+)\%",getenv} do{ s,c = replace(s,p,lambda(v)r(v) ) } while(c); if(#s) return s; } toUnicode = toUtf16;//@Deprecated fromUnicode = fromUtf16;//@Deprecated fromUnicodeIf = fromUtf16If;//@Deprecated isUnicode = isUtf16;//@Deprecated sliceUnicode = sliceUtf16;//@Deprecated concatUnicode = concatUtf16;//@Deprecated subUnicode = sliceUtf16;//@Deprecated sub = slice;//@Deprecated trimLeft = trimleft;//@Deprecated trimRight = trimright;//@Deprecated startWith = startsWith;//@Deprecated endWith = endsWith;//@Deprecated } type.isString = function(v){ var t = type(v); return t == "string" || t == "buffer"; } /**intellisense(string) table( = 解析以行为单位的字符串属性表。\n类似功能的 string.list 支持用引号包含跨行的字段值,\n但 string.table 仅将引号作为字面值处理。 table(.(字符串,键值分隔模式,行分隔模式,启用内联注释) = 解析以行为单位的字符串属性表。\n除参数@1 以外其他所有参数都可以省略。\n键值分隔模式默认为 "\s*[\:=]\s*",也就是忽略前后空白的冒号或等号。\n行分隔符默认兼容回车换行、换行、单回车等行分隔符。\n忽略以 `#` 或 `;` 号开始的行。\n启用内联注释则忽略键值对后空格加 `#` 或 `;` 号引导的注释 splitEx( = 使用模式匹配语法拆分字符串,返回拆分后的字符串数组。\n此函数与 string.lines 迭代器使用相同的拆分规则。 splitEx(.(字符串,分隔符模式串,最大拆分次数,开始位置) = \n使用模式匹配语法拆分字符串,返回拆分后的字符串数组。\n参数 @1 传入 null 值或空字符串返回空数组。\n\n分隔符模式串可用括号创建捕获组,首个捕获组如下处理:\n- 模式串尾部有 $ 符号,则捕获组放到上个拆分结果尾部。\n- 模式串头部有 ^ 符号,则捕获组放到下个拆分结果头部。\n- 模式串头部有^ 符号尾部有 $ 号则捕获组本身添加到返回数组中。\n\n省略分隔符模式则按行拆分,\n兼容回车、换行、回车换行等不同换行风格,空行不合并。\n\n最大拆分次数可省略(不限次数),分隔符单独加入拆分结果时拆分次数会对齐为奇数。\n开始位置以字节为单位,省略则默认从开始拆分。 lines( = 创建用于for in 语句的迭代器按行拆分字符串。\n可用模式串自定义行分隔符,此函数与 string.splitEx 函数使用相同的拆分规则。\n\n可将返回迭代器传入 table.array 生成数组。\n按行读取文件请使用 io.lines 函数。 lines(.(字符串,行分隔符,列分隔符,最大列数) = \n按行拆分参数 @1 传入的字符串,传入 null 或空串字符串忽略不操作。\n可选用参数 @2 自定义行分隔符,支持模式匹配语法。\n可选用参数 @3 自定义列分隔符,支持模式匹配语法。 \n\n所有分隔符模式串可用括号创建捕获组,首个捕获组如下处理:\n- 模式串尾部有 $ 符号,则捕获组放到上个拆分结果尾部。\n- 模式串头部有 ^ 符号,则捕获组放到下个拆分结果头部。\n- 模式串头部有^ 符号尾部有 $ 号则捕获组本身拆分为一个单位。\n如果返回行分隔符,则迭代器的第 2 个循环变量为 true。\n\n可选用参数 @4 限定最大拆分列数目。\n\n如果不指定列分隔符则循环返回字符串,否则返回列数组。 gfind(字符串,模式串,开始位置) = @for i,j,group1 in string.gfind( __/*查找字符串*/,"(.)") { } each( = 创建适用于 for in 语句的迭代器,\n用于在文本中逐行搜索匹配的文本,支持模式匹配语法。\n\n此函数与 string.gmatch 相似,每次迭代都会返回匹配的字符串(多个捕获分组则返回多个迭代变量)。\n但 string.each 的匹配目标是文本行(不跨行),例如模式 `^` 或 `$` 在此函数里匹配的是行首与行尾。\n\n可将返回迭代器作为 table.array 的参数以生成数组 each(.(字符串,模式串,行分隔符) = 必须使用参数 @2 指定模式表达式(匹配目标为单个文本行)。\n迭代变量为匹配的字符串,如果有捕获分组则迭代变量的个数等于捕获组的个数。\n\n参数 @3(行分隔符)也支持模式匹配语法,省略则默认为`<\r*\n>|\r` eachChar(__/*字符串*/) = 创建一个遍历文本中所有字符的迭代器,迭代器可用于 for in 语句。\n调用 string.gmatch 并将模式串参数指定为 `:|.` 也可以遍历所有字符。\n或者不指定参数调用 string.split 函数可将字符串拆分为字符串(单字符)数组。 cmpMatch( __,"" ) = 使用完全匹配比较字符串,忽略大小写,相同返回 true。\n否则使用模式匹配搜索子串,忽略大小写,找到返回 true。\n改用 string.indexOf 函数可禁用模式匹配查找子串。 concatUtf16(.(str,->->->) = 将所有参数转换为 UTF-16 字符串并连接后返回。\n参数可以是数值,字符串,UTF-16 编码字符串。\n忽略 null 值参数 isUtf8(__) = 快速检测字符串是否包含UTF8编码\n空字符串返回null loadcode( = 加载并执行 aardio 代码或文件,返回 HTML 模板输出的 HTML 代码\n如果当前应用未定义 response 对象,请使用 print 函数替代。\n此函数也可以用于非 HTML 格式的任意字符串模板,\n但非 HTML 格式的字符串开始部分必须是 aardio 模板标记 loadcode(.("代码文件",->->->) = 加载并执行 aardio 代码或文件,\n返回 HTML 模板输出的 HTML 代码,失败返回空值,错误信息。\n参数@1,与 loadcode 函数相同,其他参数作为模板参数传给被调用的文件,\n在被调用文件的函数外部可使用 owner 参数获取首个模板参数,\n也可以使用...获取多个模板参数 crlf(.(字符串,回车换行,合并空行数) = 自动调用 tostring 函数转换传入参数 @1 为字符串。\n此函数格式化参数 @1 的回车换行或单独的回车换行符为参数 @2 指定的换行标记。\n参数 @2 默认为 '\x0D\x0A' ,如果改为为 '\x0A' 则格式化为单个换行符。\n可选用参数 @3 指定合并空行后保留的最大空行数(单换行不是空行),省略则不合并。\n\n注意字符串字面值解析换行的规则:\n双引号或反引号内字符串只有换行没有回车,\n单引号内字符串解析时忽略所有回车换行,\n使用/*块注释*/包含字符串则总是将换行规范解析为回车换行组合 matches(.("字符串","模式串") = 全局匹配并将匹配结果返回为数组\n每次匹配成功的多个返回值存为成员数组\n即使没有匹配到任何结果,也会返回一个空数组 search(.(回调函数,字符串,模式串,->->->) = 模式匹配搜索.\n\n可以指定1个或多个模式串,\n此函数使用前面表达式的结果作为后面表达式的查询字符串,\n每一个模式串都支持全局搜索并可以返回多个匹配结果,\n最后一个表达式的匹配结果作为参数回调参数@1指定的函数.\n\n每一个模式串参数都可以使用函数或 lambda表达式替代,\n用于作为筛选器筛选上次的匹配结果,筛选器可以返回新的字符串,\n返回非字符串类型则用于指定是否保留上次的匹配结果,\n\n如果参数@1是一个数组,则将匹配结果添加到该数组,如果有多个捕获分组则返回二维数组,\n如果参数@1是数组则返回该数组,否则函数无返回值 map( = 搜索并返回搜索结果数组,\n并调用映射函数转换数组中的每个匹配结果为新的值,\n\n注意如果模式串中使用括号指定了多个分组,\n映射函数会有多个对应的回调参数 map(.(字符串,模式,映射函数) = 参数@1指定要查找的字符串,\n参数@2可以指定模式串,或包含多个表达式的数组,\n省略则默认为`[-\d]+`,并且参数@3的默认值会被更换为tonumber\n可选用参数@3指定映射函数,\n\n返回值为匹配的字符串数组,如果有多个捕获分组则返回二维数组\n如果参数@2不是数组而是表,则返回相同结构的表,\n每个键对应的值更新为参数表中同名键指定的模式串的匹配结果。 repline( = 按行替换字符串,返回替换后的字符串,\n此函数仅返回替换后的新字符串,只有一个返回值 repline(.(源字符串,模式串,替换串,替换次数) = 模式串用于匹配所有的单行文本,\n替换串与 string.replace 用法相同\n替换次数指的也是每一行内部进行替换的最大次数,不指定则不限制 repline(.(源字符串,模式串,替换函数,替换次数) = 模式串用于匹配所有的单行文本,\n替换函数与 string.replace 用法相同\n,\n替换次数指的也是每一行内部进行替换的最大次数,不指定则不限制 repline(.(源字符串,模式串,替换表,替换次数) = 模式串用于匹配所有的单行文本,\n替换表与 string.replace 用法相同\n,\n替换次数指的也是每一行内部进行替换的最大次数,不指定则不限制 replaceUnmatched( = 在一个或多个与指定模式不匹配的部分进行替换 replaceUnmatched(.(源字符串,替换模式串,替换对象,排除模式串1,排除模式串2->->->) = 在源字符串中保留与一个或多个排除模式串匹配的部分,\n然后对剩余的部分进行单独替换。\n\n"替换模式串","替换对象"等参数与 string.replace 函数要求一致,\n"替换对象"可以是新的字符串、替换表或替换函数。\n可以指定一个或任意多个"排除模式串"。\n函数返回替换后的字符串与替换次数。 reduceReplace( = 连续匹配多个模式串参数,\n对上一个匹配的首个返回值继续应用下一个模式串参数进行匹配。\n然后替换最后匹配的字符串。\n\n这个函数可以将复杂的模式匹配分为更简单的多个匹配步骤,\n并可将 `%()` 这样无法拆分的对称匹配进一步细分并应用新的模式串进行局部匹配,\n并用最后一个参数指定的“替换对象”替换最终匹配的部分。 reduceReplace(.(源字符串,模式串1,->->->模式串n,替换对象) = 对参数 @1 指定的源字符串进行替换。\n可指定 1 个或多个模式串参数,对上一个模式匹配的首个结果应用下一个模式串参数匹配。\n如果在模式串中指定了捕获组,则第一个捕获组之外的部分将被丢弃。\n并将最后匹配的部分替换为最后一个参数指定的替换对象。\n\n替换对象支持 string.replace 支持的字符串、函数、表等替换对象,\n替换对象的规则也是相同的,具体请查看该函数说明。 reduce( = 连续匹配多个模式串参数,对上一个匹配的首个返回值继续应用下一个模式串参数进行匹配。\n逐步完成任务并返回最终匹配结果。\n\n这个函数可以将复杂的模式匹配分为更简单的多个匹配步骤,\n并可将 `%()` 这样无法拆分的对称匹配再次拆分并应用新的模式串进行局部匹配。 reduce(.(字符串,模式,->->->) = 参数 @1 指定要查找的字符串。\n参数 @2 开始指定一个或多个模式串。\n使用前一个模式串的首个匹配结果作为后面一次匹配的条件,\n逐步缩减并返回最终匹配结果。\n也可以在参数 @2 中使用一个数组指定多个模式串。 removeBom(.(字符串) = 如果字符串开始为UTF8 BOM,则返回移除该 BOM 的字符串。\n如果字符串开始为 UTF-16 BOM,则移除 BOM 并返回转换为 UTF-8 编码的字符串,\n否则直接返回参数 getenv(.("变量名") = 读取当前进程环境变量\n成功返回字符串,失败返回 null setenv(.("变量名","变量值") = 设置当前进程环境变量\n参数@2为 null 或省略则删除参数@1指定的环境变量 expand( = 重复替换直到找不到匹配,\n可用于展开字符串中的环境变量 expand(.(字符串,查找模式串,替换函数) = 在字符串中重复执行替换操作,\n直到参数@2指定的模式串找不到匹配,\n省略参数@2,@3则默认展开百分号包含的进程环境变量\n可用于展开文件路径中的环境变量\n注意即使替换函数返回null,此函数仍然会替换为空串,\n如果替换结果为空字符串,此函数返回 null end intellisense**/ /*****intellisense() _CP_ACP=@0/*_CP_ACP*/ _CP_UTF16_LE=@1200/*_CP_UTF16_LE*/ _CP_UTF16_BE=@1201/*_CP_UTF16_LE*/ _CP_UTF8=@65001/*_CP_UTF16_LE*/ end intellisense*****/