20190529更新

1 增加测试用例
2 修复中文查找可能导致越界的bug
3 strstr改为不使用二分(效率会慢一些,但匹配结果相对可控),推荐使用strstrs_ext

==================================================================================

20190529:windows上建议使用strstrs_ext,linux上在数据不匹配的场景好像strstrs_normal更快一点。我把测试效率代码附上,有需要的可以自己验证。

从我自己测试的效率对比猜测,linux上gcc的strstr应该不是普通的暴力匹配法,网上的说法不正确。

==================================================================================

平时项目中有时需要用到在字符串中搜索两个或更多的关键字的情景。例如:将字符串"ab|cd#ef|"按竖线或者井号做分隔

如果是大项目,一般会采用正则表达式做处理。但有时写个小程序,不想因此引进一个正则库,所以我自己写了一个支持多关键字版本的字符串查找函数strstrs

函数说明:

 #include <stdio.h>
#include <windows.h> #ifndef IN
#define IN
#endif //函数说明:在字符串中搜索指定的关键字,支持1-nCnt个关键字
//strToFind 待查找字符串 不允许为空
//strKeywords 搜索关键字字符串数组 不允许为空 数组元素不允许为空(NULL),但可以是空串("")
//nCnt 关键字个数
//pFound 查找到的关键字在字符串数组的位置 不允许为空
//返回值:
//1 如果关键字存在空串,则返回strToFind
//2 如果找不到关键字则返回NULL
//3 如果找到关键字,则返回关键字在strKeywords中的位置(位置从0开始) //使用哈希加二分查找实现
const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
//使用哈希加链接实现 推荐使用
const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
//依次查找关键字的实现
const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound); //以下是为了使用方便而增加的一些重载,没多大意义
char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound); char *strstrs(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_ext(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
char *strstrs_normal(IN char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound); const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int pFound);
const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound);
void tets_strstrs(int nStep); // 0 strstrs 1 strstrs_ext 2 strstrs_normal

函数实现及相应测试代码:

// stdafx.cpp : source file that includes just the standard includes
// sqlite_test.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information #include "stdafx.h"
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h> // TODO: reference any additional headers you need in STDAFX.H
// and not in this file const char *strstrs(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs_ext(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs_normal(const char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), strKeywords, nCnt, pFound);
} const char *strstrs(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} const char *strstrs_ext(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} const char *strstrs_normal(const char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs_ext(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_ext(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} char *strstrs_normal(IN char *strToFind, IN char *strKeywords[], size_t nCnt, int *pFound)
{
return strstrs_normal(const_cast<char *>(strToFind), (const char **)strKeywords, nCnt, pFound);
} typedef struct tagKeyPos
{
const char *m_str;
size_t m_nIdx;
size_t m_strLen;
}KeyPos; int __strstrs_cmp(const void *p1, const void *p2)
{
const KeyPos *pLeft = (KeyPos *)p1, *pRight = (KeyPos *)p2;
int nCmp = strcmp(pLeft->m_str, pRight->m_str);
if (nCmp == )
{
return pLeft->m_nIdx - pRight->m_nIdx;
} return nCmp;
} /*
//lower_bound
KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
{
KeyPos *pBeg = pRealBeg;
KeyPos *pEnd = pRealEnd; KeyPos *pEqal = NULL;
while (pBeg != pEnd)
{
pEqal = pBeg + (pEnd - pBeg) / 2;
int nCmp = memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen );
if (nCmp == 0)
{
//若相等,则往前找,直至找到最后一个相等的元素
while (pEqal != pBeg)
{
pEqal--;
if (memcmp( pEqal->m_str, pKey->m_str, pEqal->m_strLen ))
{
return pEqal + 1;
}
} return pBeg;
}
else if (nCmp > 0)
{
//中值比目标值大
pEnd = pEqal;
}
else
{
//中值比目标值小
pBeg = pEqal + 1;
} } return pRealEnd;
}
*/ KeyPos *__strstrs_find_first(KeyPos *pRealBeg, KeyPos *pRealEnd, size_t *pKeyLenArr, KeyPos *pKey)
{
KeyPos *pBeg = pRealBeg;
KeyPos *pEnd = pRealEnd; while (pBeg != pEnd)
{
int nCmp = memcmp( pBeg->m_str, pKey->m_str, pBeg->m_strLen );
if (nCmp == )
{
return pBeg;
} ++pBeg;
} return pRealEnd;
} char *strstrs(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); //记录各个关键字首字符到集合中 后面判断用
bool mpFirstChar[] = {}; //这里如果用位图,可以节省不少空间
for (size_t i = ; i < nCnt; i++)
{
//linux和win的char类型定义不一样 这里统一强制转换一下
assert(strKeywords[i] != NULL);
//使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
mpFirstChar[(unsigned char)strKeywords[i][]] = true;
if (strKeywords[i][] == '\0')
{
*pFound = i;
return strToFind;
}
} KeyPos *sortKeywords = new KeyPos[nCnt];
for (size_t i = ; i < nCnt; ++i)
{
sortKeywords[i].m_str = strKeywords[i];
sortKeywords[i].m_strLen = strlen(strKeywords[i]);
sortKeywords[i].m_nIdx = i;
}
//不能排序,会导致关键字位置混乱
//qsort(sortKeywords, nCnt, sizeof(KeyPos), __strstrs_cmp); //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
unsigned char *p = (unsigned char *)strToFind;
KeyPos key;
KeyPos *pEnd = sortKeywords + nCnt;
KeyPos *pResult = NULL;
while (*p)
{
//判断当前字符是否在关键串首字符集中
if (mpFirstChar[*p])
{
key.m_str = (char *)p;
pResult = __strstrs_find_first(sortKeywords, pEnd, NULL, &key);
if (pResult != pEnd)
{
*pFound = pResult->m_nIdx;
delete []sortKeywords;
return reinterpret_cast<char *>(p);
}
} p++;
} delete []sortKeywords;
return NULL;
} typedef struct tagKeyPosExt
{
size_t m_strLen;
size_t m_strIdx;
struct tagKeyPosExt *m_next;
}KeyPosExt; char *strstrs_ext(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//20190522 修改字符串有中文会导致内存访问异常的bug
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); //仿内存池 减少new调用次数
KeyPosExt *memPool = new KeyPosExt[nCnt]; //注意:memPool分配失败会抛异常
memset(memPool, , nCnt * sizeof(KeyPosExt));
int nUsed = ; //记录各个关键字首字符到集合中 后面判断用
KeyPosExt mpFirstChar[];
memset(mpFirstChar, , sizeof(mpFirstChar));
for (size_t i = nCnt - ; i != (size_t)-; --i)
{
KeyPosExt *pPos = &memPool[nUsed++];
//如果同一个首字符对应多个关键字,则用链表连起来
assert(strKeywords[i] != NULL);
pPos->m_strIdx = i;
pPos->m_strLen = strlen(strKeywords[i]); if (pPos->m_strLen == )
{
*pFound = i;
delete []memPool;
return strToFind;
} //把新的节点插到最前面
//使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
KeyPosExt *pLast = &mpFirstChar[(unsigned char)strKeywords[i][]];
pPos->m_next = pLast->m_next;
pLast->m_next = pPos;
} //使用unsigned char 确保char类型是负数时强制转换不会超过256而越界
unsigned char *p = (unsigned char *) strToFind;
while (*p)
{
//判断当前字符是否在关键串首字符集中
for (KeyPosExt *pPos = mpFirstChar[*p].m_next; pPos != NULL; pPos = pPos->m_next)
{
//遍历以当前字符开头的关键串,挨个比较 看是否有匹配的
if (memcmp(p, strKeywords[pPos->m_strIdx], pPos->m_strLen) == )
{
*pFound = pPos->m_strIdx;
delete []memPool;
return reinterpret_cast<char *>(p);
}
} p++;
} delete []memPool;
return NULL;
} char *strstrs_normal(char *strToFind, const char *strKeywords[], size_t nCnt, int *pFound)
{
//作者:皇家救星 创建于:2016-10-19
//有bug请发送邮件至89475049@qq.com 邮件主题注明:strstrs问题反馈
//20190522 修改字符串有中文会导致内存访问异常的bug
//异常参数判断
assert(strToFind != NULL);
assert(strKeywords != NULL);
assert(pFound != NULL);
assert(nCnt > ); char *p = NULL;
for (size_t i = ; i < nCnt; i++)
{
assert(strKeywords[i] != NULL);
if (strKeywords[i][] == '\0')
{
*pFound = i;
return strToFind;
}
} for (size_t i = ; i < nCnt; i++)
{
assert(strKeywords[i] != NULL);
if ((p = strstr(strToFind, strKeywords[i])) != NULL)
{
*pFound = i;
return p;
}
}
return NULL;
} //准确性测试
int tets_strstrs1()
{
const char *strKeywords[] = {"", "select", "union", "or", "customer", "subsid",
"", "group_id", "test", "from", "truncate", "s", "english1", "", "皇家"};
const char *strSqls[] = {
"select * from dual",
"drop table",
"truncate",
"english",
"goodby",
"get 123",
"123 get",
" from"
"D",
"s",
"89sfs89",
"or",
"sor",
"orunion",
"unionor",
"83eejr3r9r9r33302002013345331224312343",
"去9999给",
"去皇家救星给"
}; for (int i = ; i < sizeof(strSqls) / sizeof(strSqls[]); ++i)
{
bool bFoundNormal = false;
int nFoundNormal = ;
if (NULL !=
strstrs_normal(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundNormal))
{
bFoundNormal = true;
} bool bFoundExt = false;
int nFoundExt = ;
if (NULL !=
strstrs_ext(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFoundExt))
{
bFoundExt = true;
} bool bFound = false;
int nFound = ;
if (NULL !=
strstrs(strSqls[i], strKeywords, sizeof(strKeywords) / sizeof(strKeywords[]), &nFound))
{
bFound = true;
} if ((bFound != bFoundExt || bFound != bFoundNormal)
|| (nFound != nFoundExt /*|| nFound != nFoundNormal*/))
{
printf("error! strSqls[i] = [%s]\n", strSqls[i]);
printf("bFound = %d nFound = %d\n", bFound, nFound);
printf("bFoundNormal = %d nFoundNormal = %d\n", bFoundNormal, nFoundNormal);
printf("bFoundExt = %d nFoundExt = %d\n", bFoundExt, nFoundExt);
return - - i * ;
}
} return ;
} //效率比较及准确性测试函数
void tets_strstrs(int nStep)
{
const int max_length = ; //max_length必须大于1024
const int max_keyword = ;
char *strToFound = new char[max_length + ]; //待查找的字符串
char *strBackup = new char[max_length + ];
char *strKeywords[max_keyword]; //关键字数组
const char strBase64[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; //为避免结果全是找不到关键字,随机将一个关键字复制到strToFound中
//这样肯定会有找到关键字的情况,结果更有意义
bool arrayFoundFlags[max_keyword] = {}; //标记是否把关键字复制到strToFound中
int arrayFoundIdxs[max_keyword] = {}; //待替换的关键字(序号)
int arrayFoundBeg[max_keyword] = {}; //在strToFound替换关键字的起始位置 if (tets_strstrs1() != )
{
printf("函数功能验证失败\n");
return;
} srand((int)time(NULL));
//初始化要查询的字符串
for (int i = ; i < max_length; i++)
{
strToFound[i] = strBase64[rand() % ];
}
strToFound[max_length] = '\0';
fprintf(stderr, "strToFound = [%s]\n", strToFound); //初始化查询关键字
for (int i = ; i < max_keyword; i++)
{
size_t nKeyLen = max_length / ;
size_t nKeyLenMin = ;
strKeywords[i] = new char[nKeyLen + ]; if (nKeyLen < nKeyLenMin)
{
fprintf(stderr, "max_length is too small\n");
exit();
}
int nLen = rand() % (nKeyLen - nKeyLenMin) + nKeyLenMin;
for (int j = ; j < nLen; j++)
{
strKeywords[i][j] = strBase64[rand() % ];
}
strKeywords[i][nLen] = '\0'; //为避免随机结果都是查不到的情况,这里增加一些干预
//if (0 != (rand() % 10))
// {
// //随机抽取约9/10的关键字 复制到待查字符串中
// arrayFoundFlags[i] = true;
// arrayFoundIdxs[i] = rand() % (i + 1);
// arrayFoundBeg[i] = 0;
// } fprintf(stderr, "strKeywords[%d] = [%s]\n", i, strKeywords[i]);
fprintf(stderr, "%d: %d %d %d\n", i, arrayFoundFlags[i], arrayFoundIdxs[i], arrayFoundBeg[i]);
}
fflush(stderr);
printf("RESULT: 函数类型 关键字总数 总耗时 总共找到次数\n");
for (int cmpType = ; cmpType < ; cmpType++)
{
int nSn = ;
double total_start = GetTickCount();
for (size_t nCnt = ; nCnt < max_keyword; nCnt++)
{
bool bSetFound = arrayFoundFlags[nCnt];
int nBeg = ;
int nChange = ;
int idxKeyword = ;
if (bSetFound)
{
//把关键字替换到字符串中 这样能保证字符串肯定包含想要的字符串
idxKeyword = arrayFoundIdxs[nCnt];
nChange = strlen(strKeywords[idxKeyword]);
nBeg = arrayFoundBeg[nCnt];
memcpy(strBackup, strToFound + nBeg, nChange);
strBackup[nChange] = '\0';
memcpy(strToFound + nBeg, strKeywords[idxKeyword], nChange);
} double start = GetTickCount();
int nFoundCnt = ; //待查字符串从短到长
for (int nStrlen = ; nStrlen < max_length; nStrlen += nStep)
{
//末尾要有\0 所以这里行把末尾字符备份起来 用\0覆盖 后面调用strstrs后再替换回去
char cBak = strToFound[nStrlen];
strToFound[nStrlen] = '\0';
int nFound = -;
const char *p;
switch (cmpType)
{
case :
p = strstrs(strToFound, strKeywords, nCnt + , &nFound);
break;
case :
p = strstrs_ext(strToFound, strKeywords, nCnt + , &nFound);
break;
default:
p = strstrs_normal(strToFound, strKeywords, nCnt + , &nFound);
break;
} //fprintf(stderr, "cmpType %d %d %d\n", cmpType, nSn, nFound);
nSn++;
if (p != NULL)
{
nFoundCnt++;
}
else
{
//假设明明有把关键字拷进去但还是返回找不到,说明结果有问题
if (bSetFound && ((nBeg + nChange) <= nStrlen))
{
printf("cmpType = %d ###############################error!\n", cmpType);
printf("strToFound = [%s], nStrlen = %d, nCnt = %d\n", strToFound, nStrlen, nCnt);
printf("strKeywords[arrayFoundIdxs[nCnt]] = [%s], nBeg = %d, nChange = %d\n",
strKeywords[arrayFoundIdxs[nCnt]], nBeg, nChange);
exit();
// switch (cmpType)
// {
// case 0:
// p = strstrs(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// case 1:
// p = strstrs_ext(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// default:
// p = strstrs_normal(strToFound, strKeywords, nCnt + 1, &nFound);
// break;
// }
}
} strToFound[nStrlen] = cBak;
}
double end = GetTickCount();
//函数类型 关键字序列 耗时 总共找到次数
printf("RESULT: %d %d %f %d\n",
cmpType, nCnt + , end - start, nFoundCnt);
fflush(stdout);
fflush(stderr); // if (nFoundCnt == 499)
// {
// printf("pre strToFound = [%s], strBackup = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d strKeywords[idxKeyword] %s\n",
// strToFound, strBackup, nCnt, nBeg, nChange, idxKeyword, strKeywords[idxKeyword]);
// } if (bSetFound)
{
memcpy(strToFound + nBeg, strBackup, nChange);
}
//
// if (nFoundCnt == 499)
// {
// printf("strToFound = [%s], nCnt = %d nBeg %d nChange %d idxKeyword %d\n", strToFound, nCnt, nBeg, nChange, idxKeyword);
// }
} double total_end = GetTickCount();
fprintf(stderr, "总共耗时[%f]\n", total_end - total_start);
} //TODO: 此处应该要释放内存
delete []strToFound;
delete []strBackup;
for (int i = ; i < max_keyword; i++)
{
delete []strKeywords[i];
}
}

函数效率比较图:

0 代表strstrs

1 代表strstrs_ext

2 代表strstrs_normal

可以看出,strstrs_ext比较稳定,而且效率也比较高。

在关键字列表都与查找字符串不匹配情况trstrs_normal表现好过strstrs

在关键字列表都与查找字符串基本都存在匹配项情况strstrs表现好过strs_normal

在任何情况下strstrs_ext都表现 最好

一个在字符串中查找多个关键字的函数strstrs(三种不同算法实现及效率分析)的更多相关文章

  1. 网络中,FIFO、LRU、OPT这三种置换算法的缺页次数

    FIFO.LRU.OPT这三种置换算法的缺页次数 转载  由于要考计算机四级网络,这里遇到了问题,就搜了一些资料来解疑. 考虑下述页面走向: 1,2,3,4,2,1,5,6,2,1,2,3,7,6,3 ...

  2. C++中三种传递参数方法的效率分析

    众所周知,在C++中有三种参数传递的方式: 按值传递(pass by value) #include <iostream> using namespace std; void swap(i ...

  3. js实现从字符串中查找出现次数最多的字符的两种解决办法

    方法一:正则表达式匹配 var str = "adadfdfseffserfefsefseeffffftsdg"; ; var result = ""; whi ...

  4. 1.3 正则表达式和Python语言-1.3.5使用 search()在一个字符串中查找模式(搜索与匹配 的对比)

    1.3.5 使用 search()在一个字符串中查找模式(搜索与匹配的对比) 其实,想要搜索的模式出现在一个字符串中间部分的概率,远大于出现在字符串起始部分的概率.这也就是 search()派上用场的 ...

  5. hiho1482出勤记录II(string类字符串中查找字符串,库函数的应用)

    string类中有很多好用的函数,这里介绍在string类字符串中查找字符串的函数. string类字符串中查找字符串一般可以用: 1.s.find(s1)函数,从前往后查找与目标字符串匹配的第一个位 ...

  6. Excel-判断一个文本字符串中是否包含数字! 判断一个文本字符串是否是纯汉字!

    0.判断一个文本字符串中是否包含数字!/判断一个文本字符串是否是纯汉字! 公式=IF(LENB(A1)=2*LEN(A1),"都是汉字","含有非汉字字符") ...

  7. ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?

    问题: ARM微处理器中支持字节.半字.字三种数据类型,其中,字需要4字节对齐(地址的低两位为0).半字需要2字节对齐(地址的最低位为0).我想问的是括号中的内容是什么意思呢?请牛人帮忙解释一下!谢谢 ...

  8. PAT 10-1 在字符串中查找指定字符

    百度了一下另外两位同学的做法,都是先判断是否匹配,然后再用一个for()循环输出,我当然也是先判断,然后,就直接puts(),还是巧妙一点,题设要求及代码实现如下 /* Name: Copyright ...

  9. [LeetCode] Find And Replace in String 在字符串中查找和替换

    To some string S, we will perform some replacement operations that replace groups of letters with ne ...

随机推荐

  1. Django runserver show client ip

    get path of basehttp.py $ python >>> import site >>> site.getsitepackages() ['/usr ...

  2. css3响应式布局

    响应式布局 分栏布局,-webkit-column-width(定义每栏的宽度,会根据每栏宽度自动分成若干栏) <style> .wrap {width: 900px; border: 1 ...

  3. 关于电脑开机不出现桌面即不启动explorer.exe桌面程序--------正解

    针对这个问题,一开始的思路是,把自己写的界面小程序(Win.exe)放在Windows启动文件夹中, 效果到是界面程序自启动了,但是还是先出现的桌面,然后才的启动的界面程序(Win.exe),并不是我 ...

  4. JavaScript省市联动

    <html> <head> <title>JS省市二级联动菜单,整理收集.</title> </head> <body bgcolor ...

  5. 关于User&nbsp;Defined&nbsp;Runtime&nbsp;Attributes的小技巧

    在用XIB里自定制view,button,label...的一些属性时,例如边框宽度,边框颜色等,如下图:

  6. MySQL 删除数据库

    MySQL 删除数据库 使用 mysqladmin 删除数据库 使用普通用户登陆mysql服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库. 所以我们这边使用root用户登录,root用 ...

  7. 逆向iOS SDK -- _UIImageAtPath 的实现(SDK 5.1)

    注释过的反汇编代码:http://pan.baidu.com/share/link?shareid=3491166579&uk=537224442 伪代码(不精确,仅供参考): NSStrin ...

  8. 关闭iOS的自动更新

    Safari打开网址https://oldcat.me/web/NOOTA9.mobileconfig,安装描述文件,就不会自动下载和提示更新最新的iOS了

  9. js变量声明与赋值以及函数声明

    if (!("a" in window)) { var a = 1; } alert(a); 结果:undefined 分析: 首先,所有的全局变量都是window的属性,语句 v ...

  10. JQuery执行函数与window.onload函数

    JavaScript和HTML之间的交互: 1.通过用户和浏览器操作页面时引发的事件来处理的. 2.当文档或者它的某些元素发生某些变化时,浏览器会自动生成一个事件. 例如:当浏览器装载完一个文档后,会 ...