[转载]手把手教你WEB套打程序开发_mtsoftware_新浪博客

mikel阅读(1085)

[转载]手把手教你WEB套打程序开发_mtsoftware_新浪博客.

WEB套打可选方案不多,理想的更少,利用免费控件Lodop+JavaScript实现精确套打,算是较为经典的选择。这种方案其实比较简单,利用一个htm文件就可以实现模板设计过程,几乎是“空手套”式的开发,但理解这几个步骤还是需要点时间,下面一步步详细演示说明:

第一步:建立一个空白的模板设计文件

把以下超文本代码复制到一个本地htm文件中:

0025zsLrzy6GWjHaJkK3a&690
本文模拟EMS特快专递单的程序开发,文件起名为printEMS.htm,权且称它为模板设计文件

第二步:用浏览器打开该文件

   在本地文件夹中双击该文件就可以打开,但在进入设计之前,你的机器需要安装Lodop,如果还没安装过,

请在如下地址下载安装文件(解压rar后运行那个exe文件,Lodop是一个1M左右的小文件):

http://www.lodop.net/uploads/file/sample/install_lodop32.zip

http://mtsoftware.v053.gokao.net/samples/install_lodop.rar

第三步:准备设计

   成功安装Lodop之后再次打开模板设计文件printEMS.htm,点击其中“模板设计”链接,就弹出如下空白的打印设计窗口:721e77e5t99431905ba10&690
  为了尽快定位模板中的数据位置,你需要做一张票据扫描图作为背景,当然没有扫描图也能完成,只是需要多摸索几次,费点时间而已。

  下面是我做的EMS扫描图,你把该图另存成一个jpg文件,以便我们一起完成后面的演示步骤。

721e77e5t99431b026bd0&690

第四步:装载背景图并调整图片大小

打印设计窗口,点下图所示的“装载背景图…”菜单,调入以上保存的EMS图片文件。

721e77e5t99431dc508f1&690

  装载背景图后,点上图所示的“调整背景图…”菜单,弹出下图“背景图调整”窗口,设定其中的图片宽度为209mm,高度113mm会自动变化。

  这个宽度值是我测量实际票据得来的。如果扫描图是按1:1比例获得的,那么调整背景图这一步就免了,当然要做点这点很难,所以最好还是在这里直接设置具体尺寸反倒简单。

721e77e5t99432070f02f&690

第五步:添加数据内容,开始打印测试

    点下图所示“插入文本项”菜单,添加打印内容,内容项可以拖拉或精细调整,基本对准之后,点击“预览”按钮(注意旁边的“打印”按钮是收费功能,纸上会有水印,而“预览时的打印”按钮是完全免费的,我们用后者)。

   把内容打印到薄一点的白纸上,然后在阳光下与真实票据透亮对比,以最左最上的某个内容为基准,其它内容远近调整,如此反复测试直到所有内容相互位置都对准。

   这一步先做到内容之间的相互位置对准,等下一步处理整体位置。

721e77e5t99432ee04e90&690

第六步:整体对准

   由于打印机左边距或上边距不一定是零或票据边缘有误差,所以尽管第五步打印出来的内容相互之间位置是准确的,但打印到真实票据上仍会整体偏离一些,需要进行整体位置调整。

  点击下图红圈所示的“纸钉”按钮,“纸钉”弹起后,整个设计版面就可以上下左右调整了,然后按上一步的办法打印测试,直到整体对准成功。为了避免浪费票 据,打印时仍可用薄白纸测试,注意此时透光对照时,纸张的左边沿和上边沿要与票据对齐,通过观察内容的位置来判断是否整体对准。721e77e5t9943315197bd&690

第七步:生成打印模板的程序代码

   套打测试成功后,点击第五步图中所示的“生成程序代码”菜单,出现下图结果,这些代码就是我们需要的模板程序代码,把他们复制出来,准备融合到你的页面程序中使用。

721e77e5t75b9eb8c305c&690

第八步:完成打印模板设计文件

想不想知道WEB套打有啥感觉?好,我们先做一个静态WEB页面爽一下:把第七步生成的程序代码,

插入替换第一步的空白设计文件CreatePrintPage函数内,变成如下内容:

0025zsLrzy6GWjJSl6l1d&690
把以上内容复制到另外一个htm文件printEMS_OK.htm中,双击打开它,点其中的打印预览,就可以实现简单的WEB套打了。

  以上八步基本完成了模板设计,并实现静态页面套打,但要把模板代码融合到实际的WEB程序中,还需要做些工作。

第九步:模板程序代码的使用

把以上CreatePrintPage函数进行简单改造,原函数如下:

function CreatePrintPage() {
   LODOP.PRINT_INITA(14,11,800,600,”套打EMS的模板”);
   LODOP.ADD_PRINT_TEXT(95,95,75,20,”寄件人姓名”);
   LODOP.ADD_PRINT_TEXT(123,148,194,20,”寄件人单位名称”);
   LODOP.ADD_PRINT_TEXT(158,101,238,35,”寄件人的详细地址”);
   LODOP.ADD_PRINT_TEXT(92,446,75,20,”收件人姓名”);
   LODOP.ADD_PRINT_TEXT(122,496,208,20,”收件人单位名称”);
   LODOP.ADD_PRINT_TEXT(160,460,244,35,”收件人详细地址”);
   LODOP.ADD_PRINT_TEXT(289,47,178,22,”内件品名”);
   LODOP.ADD_PRINT_TEXT(290,258,100,20,”内件数量”);
   LODOP.ADD_PRINT_TEXT(92,245,100,20,”寄件人电话”);
   LODOP.ADD_PRINT_TEXT(90,608,75,20,”收件人电话”);
};

把其中的打印内容提出来做为变量参数,函数改成如下样式:

function CreatePrintPage(strPName,strJJRXM,strJJRDW,strJJRDZ,strSJRXM,strSJRDW,strSJRDZ,strNJPM,strNJSL,strJJRDH,strSJRDH) {
   LODOP.PRINT_INITA(14,11,800,600,strPName);        //打印任务名
   LODOP.ADD_PRINT_TEXT(95,95,75,20,strJJRXM);       //寄件人姓名
   LODOP.ADD_PRINT_TEXT(123,148,194,20,strJJRDW);    //寄件人单位名称
   LODOP.ADD_PRINT_TEXT(158,101,238,35,strJJRDZ);    //寄件人的详细地址
   LODOP.ADD_PRINT_TEXT(92,446,75,20,strSJRXM);      //收件人姓名
   LODOP.ADD_PRINT_TEXT(122,496,208,20,strSJRDW);    //收件人单位名称
   LODOP.ADD_PRINT_TEXT(160,460,244,35,strSJRDZ);    //收件人详细地址
   LODOP.ADD_PRINT_TEXT(289,47,178,22,strNJPM);      //内件品名
   LODOP.ADD_PRINT_TEXT(290,258,100,20,strNJSL);     //内件数量
   LODOP.ADD_PRINT_TEXT(92,245,100,20,strJJRDH);     //寄件人电话
   LODOP.ADD_PRINT_TEXT(90,608,75,20,strSJRDH);      //收件人电话
};

这个改造后的JS函数还是很好理解的,无论写入js文件还是直接嵌在页面内都简单易用。

如果你改变了内容的字体、大小、粗斜体等格式,代码还会多一些,但总体来说比较简洁。

第十步:设置纸张高度,实现连续套打

多数套打业务的票据是连续纸,需要精确地分页,从而保证连续多页打印不偏移,

为此以上代码还要在PRINT_INITA之后加一行SET_PRINT_PAGESIZE语句:

function CreatePrintPage() {
   LODOP.PRINT_INITA(14,11,800,600,”套打EMS的模板”);

   LODOP.SET_PRINT_PAGESIZE(1,”209mm”,”113mm”,””);
//设置纸张高度
   LODOP.ADD_PRINT_TEXT(95,95,75,20,”寄件人姓名”);
   LODOP.ADD_PRINT_TEXT(123,148,194,20,”寄件人单位名称”);
   LODOP.ADD_PRINT_TEXT(158,101,238,35,”寄件人的详细地址”);
   LODOP.ADD_PRINT_TEXT(92,446,75,20,”收件人姓名”);
    LODOP.ADD_PRINT_TEXT(122,496,208,20,”收件人单位名称”);
   LODOP.ADD_PRINT_TEXT(160,460,244,35,”收件人详细地址”);
   LODOP.ADD_PRINT_TEXT(289,47,178,22,”内件品名”);
   LODOP.ADD_PRINT_TEXT(290,258,100,20,”内件数量”);
   LODOP.ADD_PRINT_TEXT(92,245,100,20,”寄件人电话”);
   LODOP.ADD_PRINT_TEXT(90,608,75,20,”收件人电话”);
};

  其中209mm这个纸宽参数意义不大,主要是113mm这个高度参数,它决定了每页的走纸距离,对连续打印影响很大。这个值是我测量实际票据高度得来的,包含纸张之间的撕孔间隙。理想的测量方式,是若干页连起来一起测量取其平均高。

  加入纸高控制后的打印预览如下,你可以连续打印两页内容到同一张长一点的白纸上,测试对照一下看看。把以上加入SET_PRINT_PAGESIZE语句的代码复制进第三个htm文件printEMS_OKM.htm试试。假如从第二页开始,内容向下偏移,说明纸张高度设置比实际票据大,就减小113mm这个参数值,否则增大它,这个参数可以精确到0.1mm。

721e77e5t9943388cd6cb&690

第十一步:让操作者自己调整位置

   以上十步实现的套打可以很精确,但都是以当前打印机为前提。如果你的打印程序要面对许多种类型的打印机,甚至一些未知的打印机类型,那么“打印维护”功能会很有用处。你可以根据情况在程序中把该功能授权给最终操作者或现场技术维护人员,让使用者自己来调整打印位置,以适应各种类型的打印机。

  打印维护的指令语句是PRINT_SETUP,进入包含该功能的在线文件PrintEMS_OKMSetup.htm,先在打印维护中调整一下打印内容或整体位置,点“应用”按钮。关闭浏览器后重新打开,进入“打印预览”,看看是否有关联变化。下图是打印维护界面,其中能看到“应用”按钮和“恢复整体缺省”按钮的位置。
721e77e5t99433c3a330e&690
以上拙笔语无伦次,请各位笑纳!!

本文参考如下资料:

http://www.lodop.net/demo.html

http://mtsoftware.v053.gokao.net/samples/PrintSampIndex.html

[转载]游戏引擎不仅是代码,更多的是完善的工具 - 麒麟子(Alex) - 博客园

mikel阅读(1034)

[转载]游戏引擎不仅是代码,更多的是完善的工具 – 麒麟子(Alex) – 博客园.

从洗脑开始

记得若干年前,在做公司引擎研发的时候,时常会念到的一句话:引擎不仅是代码,更多的是完善的工具。当时只是用这句话还激励自己,找准引擎开发的原则和位置。 而实际上,对这句话的理解甚少。时隔多年,这句话油然在耳,伴随我左右

亲身体会

后来,引擎项目砍掉了,进入了页游产品的开发。 在这个产品开发的第一周,我们就面临着动画和场景编辑问题,在脑海中第一时间浮现出的,依然是这句话。于是,我们花了两个星期来做了一个简单的动画编辑器 和场景编辑器。动画编辑器只有简单的图片导入,和锚点设置功能(因为怪物大小不一样)。 而场景编辑器,则只有图片导入,怪物摆放功能……。但正是这两个简陋的编辑器,使我们的项目能够让策划在没有程序的帮助下快速进行关卡相关的内容设计。 这也是第一次,让我感受到,工具能够给项目带来的意义,绝非那两句话可以概括的。

 

扩展与定制

换了一家公司,是做和帝国时代差不多的开发。这家公司的理念和我是一致的,就是先要开发编辑器,然后再做游戏。 这家公司开发了sprite editor,ai editor,level editor 一切的愿望都是美好的, 而唯一让我觉得神奇的,是ai editor和level editor,消耗了大量的时间。同时,内置的许多东西,使得每一次需求变更,都要程序维护相应的editor版本才能达到对应的功能支持。 现来回想起来,如果当初使用配置文件来做一些和需求相关的东西,岂不是更好

 

上层开发语言

我曾经一度认为,这辈子就靠C++吃饭了。C++这么好的语言,图形和引擎底层都是用C++写的,上层逻辑自然应该用C++写。 并且脚本语言的效率,完全是C++没法比的。

这只是当时的想法,据我所知,成都的逸海情天,在很早的时候,就已经使用 C++底层+JAVA逻辑的开发模式了。 曾经我还笑过这种方案,觉得是一堆不会C++的奇葩货弄出来的玩意儿。当我接触到UNITY3D后,我才发现,C++ + JAVA的模式,是多么的高大上啊。 C++高效率的特性用在底层无疑是不二之选,但好东西都是一把双刃剑,C++逻辑开发中遇上的各种问题,不是一己之力能够杜绝的。

现在在手机平台上,将脚本作为上层开发语言就更是比比皆是了。 原因就是那让人神往的IOS。为了游戏能够在游戏中进行更新,不得不采用脚本作为逻辑开发。这也使得引擎使用C++底层+脚本逻辑走上了正轨。 而实际上,早期的许多公司或者引擎也是这样做的。比如torque,unreal等

 

发布与布署

在端游的时代,发布和布署可能并没有受到在大的重视,只要编译好,放到适合的位置就可以了。

而随着页游联运的兴起,发布和布署的成本就随之提升了,因为会针对不同的运营商做一些功能定制,若为每个运营商开发一分支,维护起来成本就更高了。因此我 们选择在同分支下做处理,而将运营商相关的东西做一些标志,根据不同运行商进行加载。 这都还不是终点,在一定程度上,我们可以解决问题。

随着手游的兴起,先不说杂七杂八的国内Android平台,首先面对IOS和Android系统,我们的引擎就需要针对性地做一些优化处理。拿图片处理为 例,在IOS上,通常使用PVRTC 4bp格式,而在ANDROID上,则使用ETC。 如果两个版本做不同分支,就更不科学了。因此,我们需要做一些脚本化的东西,使我们的资源可以在发布前,打包或者转化为目标平台可识别的资源。 因此,在这个地方,SHELL工具,又变得不可缺少了,而不仅仅是给策划和美术使用的编辑器

 

Shell与python

很多时候,我们使用shell就可以搞定许多问题,但是,python作为一个强大的脚本语言,它提供的各种工具库不是shell能比拟的,比如文件搜 索,MD5生成,图片处理等等。 更让shell不能比的是,python是跨平台的,这就让我们在MAC,LINUX和WINDOWS上,可以复用我们写好的工具。 而shell则只需要做一些简单的平台权限相关的操作。 如果使用python能够搞定的,我们尽量使用它。 因为手机游戏的开发,很多时候MAC与windows都有需求。

Unity3D

    虽然从 来没有使用过这货开发项目,但自从2011引擎项目砍掉后,我就一直关注它,研究它。一开始,我对它的做法是很不接受的,觉得将一个引擎与工具绑定得如此 紧密,导致我在调试程序的时候,还要启动UNITY3D的IDE,是一件很不爽的事情。 很有早期使用FLASH CS来开发FLASH游戏的感觉。 一直期待UNITY3D能够像FLASH BUILDER一样,出一个纯代码的开发环境。 但后来发现,UNITY3D之所以强大,正是因为它的编辑器,而不是他那高端的组件化设计。 一个纯组件化设计的引擎,如果没有一个好的工具配合,是很难发挥效果的,甚至会多写许多代码。而组件式这种巧妙的设计,居然能够将编辑器与项目需求解耦。 也让我刷新了引擎架构方面的认知-----引擎除了工具和渲染,良好的上层结构依然重要。

    Mono平台的引入,虽然使UNITY3D发出的包略大,同时在CPU较低的机型上很吃力以外,没有任何不好的地方。许多人吐槽这东西,但我觉得,大家应该承认时代的变迁。

    Unity3d的2D支持引入虽然过晚,但充分说明Unity3d对2D方面的势头,虽然重型的MONO平台使得即使是2D游戏,也带来一定的开销,但我觉得,在保证产品稳定,快速迭代等前提下,少兼容一定量的低端设备,也是允许的。 

 

Cocos2d-x

    要说影响中国游戏开发界的开源引擎,除了早期名噪一时的OGRE,如今就只有它了。 许多人说它的架构很2,许多人说他其实就是一个山寨货, 许多人说他自己花点时间就能写出来。 这些人的对与错我们不讨论了,我们来看市场占有率。 或许这样你会说很俗。 但一个东西存在即是合理的。 一个引擎,能够满足你的项目开发需求,同时为你省下大把时间,你有多少理由不使用它? 而非要自己去DIY一个蹩脚的引擎, 你觉得你写出来的东西,坑就一定比别人少吗?

    3.x版本的cocos2d-x已经与往日不同了,我很高兴能够看到cocos2d-x在代码结构方面的革新。(不仅仅是去掉了CC前缀)

    cocostudio虽然还是一个半残品,但不得不说,触控官方出力开发一个商业级的编辑器,这在开源项目中还是很少见的。大家应该给它时间成长。 而在成长期间,还是用最适合的方案来构建自己的项目吧。试想,在cocostudio出现之前,也有无数的成功案例。

Irrlicht

这是我曾经最喜欢的引擎,它伴随着我渡过了大学生活,我在寝室里,时常阅读它的代码和注释,虽然没有特别的收获(因为完全看不明白),却使我保持了对引擎的热情。

Nicko为这个引擎开发了一个irrEdit,但随时时间的推移,这个东西已经不更新了,因为nicko发现,irrlicht没啥意 思,irrEdit和irrKlang收益又不多。于是转而投入一superCube的开发。supercube卖得还挺贵的,支持 flash,html5,android app,ios app,windows exe等发布。 功能和特性都挺NB,但是界面和实际的功能,真的好像小朋友做的。 有兴趣的朋友可以试试

 

OGRE

这是我接触的第二个引擎,它的庞大使我望而怯步。有幸在研发过程中,研究过天龙八部的代码,以及它的材质系统。 整个东西都挺OK的,而美中不足的是它就像一个仓库,什么都往里塞,而很多东西,也是停留在学术层次,如果想投入项目,还得自己改造一番。 cocos2dx可以说是很直接的了(有人说是因为2D很简单,但我觉得,是因为cocos2dx定位很明确,或者说,是因为cocos2d的定位很明 确)。 OGRE也没有附带编辑器。 而早期的项目,都不是基于UNITY3D那种解耦方式,许多都是为特定类型的游戏定制编辑器。我研究过大唐,神咒,天机,以及刚刚说的天龙八部的代码和编 辑器,都是为MMORPG定制的,且直接关联游戏内容。 这或许就是当时的引擎发展层次吧。

 

 Glitch

这是一个由Irrlicht发展而来的引擎,核心部分虽然有较多扩展,性能和特性也是Irrlicht不可同日而语的,但核心部分依然保持了 IRRLICHT的风格。 唯一不同的是,上层逻辑开发的模式,与UNITY3D如出一辙,这也是让我想到了,任何引擎,都可以慢慢的向UNITY3D的逻辑开发方式靠齐,包括 cocos2dx,更甚至是ogre。glitch由于是内部使用引擎,工具也是自家定制的,但工具的设计思路,也和unity3d颇为相似。这一点可以 说是让我十分欣赏。

 

 

……时代在发展,行业在进步,我们必须跟上大众的步伐,才能在这无硝烟的战争中,赢得属于自己的那一仗……

[转载]值得一试的8个最佳云端集成开发环境 | 前端里

mikel阅读(1613)

[转载]值得一试的8个最佳云端集成开发环境 | 前端里.

众多基于传统桌面的软件正在迁移到云端,这一点都不奇怪,基于云的集成开发环境正在不断涌现,已经有很多的开发者在使用 Github 和 Pastebin 来进行在线的协同开发。今天这篇文章挑选了8个最优秀的云端集成开发环境推荐给开发者,大家可以体验一下,看哪个适合自己。

Cloud9 IDE

基于 NodeJS 构建的在线集成开发环境,语法高亮支持 C#, C++, Python, Perl, Ruby, Scala 等等众多常用开发语言。内置的 Vim 模式非常好用,支持流行的版本控制系统,像 Git, Mercurial 和 SVN,另外它还有非常强大的插件系统,可以拓展其功能,例如借助 CSSLint 和 JSBeautify,Cloud9 就可以变成一款非常实用的代码美化工具。

2012111916534637

Codeanywhere

这款云端开发工具经常荣登各种网络上的最佳榜单,是使用体验非常友好的一款 IDE。支持 HTML, CSS, JavaScript, PHP, MySQL 等语言的语法高亮支持,还提供了 iOS, Android 和 BlackBerry 的应用,这个工具让任何人可以在任何地方进行编码开发。

另外还提供了 Dropbox 和 SFTP 支持,让开发者可以轻松备份代码和分享给合作者,最然这不是功能最全面的云端 IDE,但是它拥有的功能都是做到了极致。

Coderun Studio

如果你已经尝试的其他基于浏览器的集成开发环境都觉得不适合自己,正在寻找的使用更简单功能更强大的云 IDE,Coderun Studio 是值得一试的。它为用户提供一个跨平台的工具,可以编写 ASP.NETJavaScript,C#,HTML 和 CSS,兼容 Visual Studio。

此外,它的本地编译和调试功能都是其它云端开发工具无可比拟的。Coderun Studio 的分享功能让开发者能够通过生成的专属 URL 快速的与其他人分享代码。

Cloud IDE

虽然他们显然没有花很多的时间来了一个朗朗上口的名字,但是它作者却为这款云端 IDE 做了很大的努力,也让它成为云端集成开发环境的有力竞争者,支持 JavaScript, Ruby, Groovy, Java 等语言,特别适合 Java 开发,支持 Java servlets 和 JSP,还有 Maven。代码部署由 Heroku, CloudBees, Red Hat OpenShift 和 Cloud Foundry 提供支持。

Kodingen

基于 Web 的云端编辑器之一,通过恰当的定位在过去几年争得了很强的竞争力。它让开发人员可以进行 PHP, Python, Perl 和 Javascript 的开发,同时还支持 Django, Ruby on Rails 和 Node.js 框架。通过丰富多样的社区,可以和其它用户进行协作和共享。

ShiftEdit

接下来,我们一起看下 ShiftEdit。虽然的知名度可能没有 Cloud9 或 Coderun 那么高,不过这个多功能的基于云计算的软件还是值得研究的。无论是 Python,PHP 或Perl,ShiftEdit 都支持。用户可以通过 SFTP 把代码文件备份到 Dropbox,使用各种版本控制工具跟踪变化。它的 SSH 身份验证,代码完成和代码段功能可以无缝的完成工作流程,使开发人员能够提供工作效率。

Akshell

在云 IDE 竞争如此激烈的时代,它变得越来越难从众多集成开发环境脱颖而出了。Akshell是一个服务器端的开发环境,提供了一个轻量级的工具,是非常好的基于 JavaScript 的 Web 应用程序的编码器。它依赖于后端存储的PostgreSQL数据库,对于那些熟悉 MySQL 的开发者来说应该很容易就可以上手了。

  借助集成的 Git 控制台,部署和创建任何项目都是非常轻松的。如果你是一个很挑的 Javascript 开发者,正在寻找器快速和稳定的云端 IDE,那么 Akshell 正式你需要的。

Orion

著名的 Eclipse Java IDE 因其全面的功能和坚固的可靠性,是多年来桌面软件开发领域的中流砥柱。Orion 把 Eclipse 的丰富经验引入了云 IDE 领域,不过目前它的主要用途是前端 Web 开发,所以在大多数情况下只能编写 HTML 和 Javascript。

它还在不断发展中,我们期望在未来一年内看到更多新开发出来的功能。除了集成 Firebug 之外,其最大的卖点是它的 Eclipse 风格的用户界面和直观的布局。

未经允许不得转载:前端里 » 值得一试的8个最佳云端集成开发环境

[转载]Javascript 随机抽奖 - SkySoot - 博客园

mikel阅读(924)

[转载]Javascript 随机抽奖 – SkySoot – 博客园.

<body>

    <div style="width:365px;height:180px;border:2px solid green" id="names">

    <script>

        for(var i=1;i<=40;i++){

            document.write('<div style="width:45px;height:35px;background:#ccc;float:left;border:2px solid white;text-align:center;padding-top:7px;">'+ i +'</div>')

        }

    </script>        

    </div>

    <a href="javascript:oaction()" style="margin:5px;" >开始抽奖</a>

    <a href="javascript:clearInterval(sh)" style="margin:5px;" >停止抽奖</a>

    <script>

        var names = document.getElementById("names").getElementsByTagName("div");

        var length = names.length;

        var oldNum = 0;

        var sh;

        function run(){

            var num = Math.floor((Math.random()*40));

            names[oldNum].style.background = "#ccc";

            oldNum = num;

            names[num].style.background="green";    

        }        

        

        function oaction(){

            sh=setInterval(run,10)

        }

    </script>

</body>

[转载]韩都衣舍的小组制,是怎么被逼出来的?!(派代网)

mikel阅读(852)

[转载]韩都衣舍的小组制,是怎么被逼出来的?!(派代网).

历史的材料就放在哪儿,问题是你能得出什么智慧?韩都的小组制已经早就被大家所熟知,但是,你知道韩都的小组制在哪一个环节为什么 要实施哪一个步骤吗?你知道每个阶段韩都面临的问题提出的解决方法吗?今天,调戏电商(微信号:tiaoxiEC)就来聊聊韩都小组制的进化史。

插叙一个评价:

                                              小组制1.0:从买手到买手小组

2007年之前,彼时的中国网络市场上,有成千上万的韩风女装在销售,要么是代购,要么是抄款,每个店铺也就几十款,大家做的都一般。

赵迎光折腾了好几年电商,也开了门店,但仍然对未来要干什么仍然很迷茫,他不知道如何才能跟大家建立差异化?

2007年中旬,赵迎光接触到韩国最大的快时尚公司,一般的公司是给生产商三四款衣服,每款都生产上万件,而这家公司是直接给生产商700款衣服,具体生产哪些款式,由生产商决定。虽然款式多,但是单款订单量却少,少则数百件,多则上千件,卖得好再返单。

赵迎光恍然大悟,终于摸索到了自己梦想的未来,于是立刻尝试这种多款少量的模式。

但公司资源有限,怎么办?聚焦在做代购环节!他把重心放到培养买手上,招揽一批学生,将韩语专业和服装设计专业的搭配在一起,从韩国三千个服装品牌中挑选出一千个,分给40个人,每人每天从25个品牌的官方网站上挑出8件新品,这意味着每天有300款新品。

当时,淘宝搜索是按上新时间排序,原本赵迎光只是想使产品充足丶新鲜,却没想到赢得了流量。

这让韩都很快跟网上千千万万个韩装店铺区别开来,竞争力一下增强。

但代购有几大硬伤,比如等待时间过长,无法退换货,经常断货断色断码,性价比不高等等。在培养了买手一年之后,赵迎光决定从“代购商品”转为“代购款式”,“买手小组”雏形咋现。他们像从前一样选出款式,进行样衣采购,然后打样,选料,在国内找工厂量产。

后来,赵迎光索性不再要求每个人盯着25个品牌,而是全部打乱,买手小组开始竞争。这也是为了培养买手的独立经营意识。

但是,问题又出现了,每个买手都希望上更多的产品,却不注意库存问题,只选图片上传,买手们对供应链并无太多考虑。

这就面临着整个服装行业的根性问题:库存谁来背?

传统的企业是选款师与店长分开的,但网络上,他们是可以合二为一的,所以赵迎光决定库存深度由设计师(选款师)来决定,一般说设计师搞设计的,你让 他们去搞运营是不行的,但是实际上实践证明,配上辅助人员之后,如果真的让设计师团队小组具备了运营意识之后,你会发现库存周转会快起来。

有责任,就要有权力匹配。2009年4月,经过一年的买手培养,赵迎光抱着试试看的心理,给了买手2万元,让她自己决定生产件数丶颜色丶尺码,一旦盈利,公司和买手分成。

几个月后,这种分成制度的优势开始显现了,买手积极性上来了,他们不仅可以找到韩国最新的时尚款式,还能通过找代工厂生产,从而降低成本,把控质量。

后来,他在内部做了个试验,成立了两套班子,一套是按照传统服装公司设置三个部门:设计师部丶商品页面团队以及对接生产丶管理订单的部门;另一套系统是把三个部门的人打散,每个部门抽出一个人,三个人成立一个小组,总共十个小组。两套班子同时开工,三个月后,传统班子被停掉,公司开始试用效率更高丶产品更好的小组制生产模式。

就这样,小组制模式成形了,从原来的单个选款买手,配合视觉人员和运营人员之后,就成了买手小组。这一阶段的小组制最主要的目的是为了款数上量,减少选款风险,提高积极性。韩都也通过多款,带来了更多流量。

 

小组制2.0:内部资源市场化,大家都是二老板

2011年的时候,韩都有70个小组,小组一多,原来可以认为调配的资源,没法调了,比如公司内部的推广资源如何调配?店铺的首页,放那个小组的产品?

赵迎光索性给每个小组更高自治权,款式选择丶定价丶生产量丶促销全都由小组自己决定,小组提成根据毛利率或者资金周转率来计算,因此毛利和库存是每个小组都最关注的两个指标。在韩都衣舍的淘宝店里,很少有统一的打折促销,而是每个小组根据自己商品的情况作出促销决策,以保证毛利率和资金周转率。

对于首页资源,他们有一个内部资源市场化的机制,成立六个月以上的小组,可以竞拍位置;成立六个月以内的,首页拿出专门的位置,让大家抢,谁手快谁抢到。

当然在最重要的财权完全放开,每个小组的资金额度自由支配,而这个额度又与小组的销量直接挂钩 ,卖的越多,额度越大。在韩都衣舍,本月的资金额度 是上个月销售额的70%。比如上个月有个小组卖了500万,500万的70%是350万,那么这个月该小组可以用350万再去下新的订单。

同时,该模式下,每个小组都必须有很强的危机意识。假设一个小组是5万元“起家”,小组一定不会把这5万块钱都用去下订单。因为如果卖不出去,就再没有使用额度,小组必须开始卖库存。如果库存永远卖不出去,这个小组就永远没有额度,甚至会死掉。

死掉怎么办?死掉就“破产”“重组”呗。

他们会对各个品类的小组进行竞争排名,排名前三位的会得到奖励,后三名的会被打散重组。

(图片来源:《卖家刊》)

这样,每个小组都是一个竞争因子,也几乎就是一个小公司。这种把公司做小的理念稻盛和夫和张瑞敏都在尝试,而韩都依托互联网的基因轻装上阵,走的更远。

这一阶段的使命是解决内部资源分配问题,也是韩都整个公司架构全面小组化的阶段。产品小组若是觉得之前对应的摄影小组不够好,那就换一个;若是觉得 生产部**小组协调得力,就会分配更多任务,生产部就会有更多收入,也会更有动力。整个组织架构就像标准配件一样,可以自由对接,也确保大多数人员的收入 能够跟市场挂钩。

 

小组制3.0:为了变态的售罄率

2012到2013年,韩都有两百多个小组,七个品牌,每年将近两万款,这个阶段最头疼的是什么?

供应链!

产品质量参差不齐,库存把控不够准确。几万款产品,跟生产环节对接的工作量太大了。已经不是凭借小组就可以跟几十家工厂很好对接的了。就需要全局规划和单品精确管理。

所以,小组制又进化了,他们创建了单品全流程运营体系,并成立企划中心,用售罄率倒逼各个链条做到单款生命周期管理。

所谓单品运营,就是以单款来考虑的,这一款衣服从设计到销售,全部有数据把控。单款产品的运营模式,把每款产品赋予生命周期,都有专人精心维护,平 均下来,每个月每个小组管理七八款衣服,每款给什么位置,做什么搭配,冲击爆款能到什么程度?库存水平到什么状态需要打折,长期练下来,自然得心应手。

企划中心则根据历史数据,在年初的时候,再参考年度的波峰波谷节奏,制定目标,然后分解到各个小组,每个小组,在月度丶季度丶年度,都有细分的考核指标。企划部相当于韩都的发改委和数据中心,并且协调各小组之间的竞争。

企划中心的节奏控制对于韩都的供应链至关重要,能够让生产部及其工厂提前预测下一步的就进度,方便备料,数万款产品下单,没有节奏控制,纯粹找死。

现在韩都的售罄率能够做到95%,这在服装行业是很变态的,尤其是能够每年两万款的情况下,而据韩都分销部负责人刘景岗透露,完成这个指标压力不大。

韩都为了做到这一点,将产品分为:爆旺平滞,爆款和旺款可以返单,平款和滞款必须立即打折促销,而且要在旺销时间,稍一打折就会售出,等到了季末, 需要清仓的恶性库存就很少。这样一来,整个供应链反应更灵敏,品质也更易控制。当然这个过程是一点点摸索和改进的,没有历史数据的积累,也做不到预测。

总结说来,小组制可以做到大的共性与小的个性结合,把所有非标准化的环节全部由小组来做,产品的选款丶页面制作丶打折促销都是非标准化的环节,标准 化的环节指客服丶市场推广丶物流丶市场丶摄影等等,通称叫公务部门。再加上人资部门,财务部门,行政部门等,就完成了韩都的组织架构的三级管理。

这就是整个韩都小组制的进化史,每一步都是面临着一个核心问题,为了解决一个个问题,而一步步被逼出来,最终让整个公司组织完成了彻底的改造。

如果你只看到小组制,而没有看到小组制背后的调控部门,也无法完全复制韩都的成功,他是既有小,也有大。一项制度最核心的是精神和本质,而不只是他 外部呈现出来的形式。(敬请期待调戏电商【微信公众号:tiaoxiEC】下期内容:为什么别人学不会小组制?凡客向左,韩都向右。)

如果你看过《失控》(一本深刻影响了美国互联网的书)的话,会发现,韩都的小组制正是暗合了互联网的分布式协作特征,也是蜂式思维的体现,通过小组带动大盘。

而比《失控》更早实践这种管理思想的是稻盛和夫的阿米巴模式,在上个世纪六七十年代,稻盛和夫就用阿米巴挽救了京瓷和KDDI。

所以,小组制是一项博大精深的管理哲学,你不能把小组制简单的看做企业为了内部激励而采取的组织变革,他既是市场需求由大众化到小众化的改变,也是竞争从多元化到跨界元之后的管理应对。

这不是一个个别现象,而是整个企业界管理变革的序曲。

(更多深度剖析文章请留意《销售与市场(渠道版)》11期封面专题。本文借鉴亿邦动力丶《环球企业家》丶《卖家刊》等多家媒体资料。)

 

附小论:传统服装业的困境在哪儿

赵迎光曾经非常欣赏一段话:有一种培养叫放手:世上最困难的就是把一件你很拿手的工作交给别人,再眼睁睁看着他把事情搞砸,而你却还能心平气和不发 一言,那是培养人。世界上最容易的就是把一件你很拿手的工作交给别人,再手把手地教他把事情做对,不给他犯错机会,那不是培养人,而是锻炼你自己。

他之所以非常欣赏这句话,其实是他放手让小组长成长的依据。

对于服装企业来说,款式是最重要的,但是,这个最重要的工作却不能让老板亲自参与其中,这就是宿命,最好的老板应该培养最好的选款队伍,而不是亲自 参与。而凡客为了度过危机,陈年亲自上阵,不由得让我们为凡客的未来捏了一把汗。说到底,凡客还是一个披着互联网外衣的传统企业。(敬请期待调戏电商【微 信公众号:tiaoxiEC】下期内容:为什么别人学不会小组制?凡客向左,韩都向右。)

再反观传统的服装企业,但是大部分传统服装品牌的创始人都有设计师基因,所以很多创始人丶老板都会参与选款。

而这种方式选款容易受到精力和能力的局限,在需要大量款式的时候容易出现较高的选款失误率。并且在这种模式中负责选款和运营的人是分离的,这也导致选款师难以对市场形成敏锐的认知。

在这种环境下设计师团队和选款师很难成长,服装品牌应该赋予设计师更多的权力,进行权力下放。款式决定权和运营权的分离也不利于网络服装品牌的发展。

尤其可怕的是,行业巨头所形成的的大格局正在被韩都这些小型的选款师们一点点打散,传统服装巨头被蚂蚁雄兵一点点的丶无声无息的啃食,但是,他们四处寻找,却找不到同量级的对手单挑。

(文章首发在微信公众号:调戏电商,有爆料,有深度,上万名电商中高层的选择,你,值得关注!)

扫描二维码,快速关注摇曳生姿的【调戏电商】

[转载]使用Easy4net编写代码生成器 - 奋斗 - 博客园

mikel阅读(1285)

[转载]使用Easy4net编写代码生成器 – 奋斗 – 博客园.   在项目中经常要手动创建和数据库对应的实体类,如果数据库表比较多或者表字段比较多,那会是一个工作量非常大的事情,所以我根据自己的需求写了一个简单的代码生成工具,工具使用Easy4net框架开发。

 

下面是代码目录结构:

项目开始预备步骤:

1. 创建项目EntityCodeBuilder

2. 引入Easy4net项目源码

3. 创建Entity类库

4. 创建TableName和TableColumn类

5. 在App.config配置文件中配置数据库连接信息

TableName源码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EntityCodeBuilder.Entity
{
public class TableName
{
public string Name { get; set; }
}
}

TableColumn源码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace EntityCodeBuilder.Entity
{
public class TableColumn
{
public string Name { get; set; }
public string Type { get; set; }
public string IsIdentity { get; set; }
public string IsPrimaryKey { get; set; }
public string IsNull { get; set; }

}
}

App.config配置文件代码:


<!--<add key="DbType" value="mysql"/>
<add key="connectionString" value="Data Source=.;port=8001;User ID=test;Password=123456;DataBase=test;Min Pool Size=10;Max Pool Size=100;"/>-->

UI上的代码不细说了,主要是有几个类的代码:

TableHelper中的代码,获取数据库所有表名:

///
/// 获取数据库所有表名
///

//////
public static List GetTables()
{
SqlConnection connection = (SqlConnection)DbFactory.CreateDbConnection(AdoHelper.ConnectionString);
List tablelist = new List();
try
{
if (connection.State == ConnectionState.Closed)
{
connection.Open();
DataTable objTable = connection.GetSchema("Tables");
foreach (DataRow row in objTable.Rows)
{
TableName tb = new TableName();
tb.Name = row[2].ToString();
tablelist.Add(tb);
}
}
}
catch(Exception e)
{
throw e;
}
finally
{
if (connection != null &amp;&amp; connection.State == ConnectionState.Closed)
{
connection.Dispose();
}
}

return tablelist;
}

TableHelper中的代码,根据表名获取所有列:

///
/// 获取字段
///

/////////
public static List GetColumnField(string TableName)
{
StringBuilder sb = new StringBuilder();
sb.Append(" SELECT a.name,");
sb.Append(" b.name as type,");
sb.Append(" CASE COLUMNPROPERTY(a.id,a.name,'IsIdentity') WHEN 1 THEN '√' ELSE '' END as IsIdentity, ");
sb.Append(" CASE WHEN EXISTS ( SELECT * FROM sysobjects WHERE xtype='PK' AND name IN ( SELECT name FROM sysindexes WHERE id=a.id AND indid IN ( SELECT indid FROM sysindexkeys ");
sb.Append(" WHERE id=a.id AND colid IN ( SELECT colid FROM syscolumns WHERE id=a.id AND name=a.name ) ) ) ) THEN '√' ELSE '' END as IsPrimaryKey,");
sb.Append(" CASE a.isnullable WHEN 1 THEN '√' ELSE '' END as IsNull ");
sb.Append(" FROM syscolumns a ");
sb.Append(" LEFT JOIN systypes b ON a.xtype=b.xusertype ");
sb.Append(" INNER JOIN sysobjects c ON a.id=c.id AND c.xtype='U' AND c.name&lt;&gt;'dtproperties' ");
sb.Append(" LEFT JOIN syscomments d ON a.cdefault=d.id ");
sb.Append(" WHERE c.name = '").Append(TableName).Append("' ");
sb.Append(" ORDER BY c.name, a.colorder");

//使用Easy4net框架查询数据
List list = db.FindBySql(sb.ToString());
return list;
}

知道表名,字段名称,字段类型后,要生成实体类,需要根据数据库中的数据类型转换为C#中的类型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsDemo
{
public class TypeHelper
{
public static string GetType(string type)
{
string newType = "String";

switch (type)
{
case "varchar":
case "varchar2":
case "nvarchar":
case "char":
newType = "String";
break;
case "int":
case "integer":
case "bit":
case "smallint":
newType = "int";
break;
case "long":
case "bitint":
newType = "long";
break;
case "date":
case "datetime":
case "datetime2":
case "datetimeoffset":
newType = "DateTime";
break;
case "decimal":
case "number":
case "money":
case "numeric":
newType = "Decimal";
break;
case "double":
newType = "double";
break;
case "float":
newType = "float";
break;
}

return newType;
}
}
}

下面就是生成代码的具体步骤了:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using EntityCodeBuilder.Entity;

namespace WindowsDemo
{
public class CreateFileHelper
{
///
/// 创建类文件目录和文件
///

///所有表 ///文件目录 public static void Create(List tables, string fileDir)
{
CreateDirectory(fileDir);
foreach (TableName table in tables)
{
//实体类名称
string entityName = GenVarName(table.Name);
//实体类文件名
string filePath = fileDir + entityName + ".cs";
//文件是否存在
bool exists = File.Exists(filePath);

//创建文件
FileStream fs = new FileStream(filePath, exists ? FileMode.Open : FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);

//生成代码
string code = CreateFileHelper.BuilderCode(table.Name);

//写入代码到文件
sw.WriteLine(code);

sw.Close();
fs.Close();
}
}

///
/// 创建文件目录
///

///private static void CreateDirectory(string targetDir)
{
DirectoryInfo dir = new DirectoryInfo(targetDir);
if (!dir.Exists)
dir.Create();
}

///
/// 根据表名,生成代码
///

///表名 ///
public static string BuilderCode(string tableName)
{
string entityName = GenVarName(tableName);

StringBuilder sb = new StringBuilder();
sb.Append("using System;").Append("\n");
sb.Append("using System.Collections.Generic; ").Append("\n");
sb.Append("using System.Linq; ").Append("\n");
sb.Append("using System.Text; ").Append("\n");
sb.Append("using System.Text; ").Append("\n");
sb.Append("namespace Easy4net.Entity ").Append("\n");
sb.Append("{ ").Append("\n");

sb.Append("\t [Table(Name = \"").Append(tableName).Append("\")] ").Append("\n");
sb.Append("\t public class ").Append(entityName).Append("\n");
sb.Append("\t { ").Append("\n");

List columns = TableHelper.GetColumnField(tableName);
foreach (TableColumn column in columns)
{
string type = TypeHelper.GetType(column.Type);
if (column.IsPrimaryKey == "√")
{
//[Id(Name = "UserID", Strategy = GenerationType.INDENTITY)]
string strategy = "GUID";
if (column.IsIdentity == "√")
{
strategy = "INDENTITY";
}

sb.Append("\t\t").Append("[Id(Name = \"").Append(column.Name).Append("\", Strategy = GenerationType.").Append(strategy).Append(")]").Append("\n");
}
else
{
sb.Append("\t\t").Append("[Column(Name = \"").Append(column.Name).Append("\")]").Append("\n");
}

string fieldName = GenVarName(column.Name);
sb.Append("\t\t").Append("public ").Append(type).Append(" ").Append(fieldName).Append("{ get; set; } \n\n");
}

sb.Append("\t } ").Append("\n");
sb.Append("} ").Append("\n");

return sb.ToString();
}

///
/// 将数据库中变量名改为驼峰命名
/// 如 user_name 改为 UserName
///

///变量名 ///
public static string GenVarName(string name)
{
string first = name.Substring(0, 1);
name = name.Substring(1, name.Length - 1);
name = first.ToUpper() + name;

int index = name.IndexOf("_");
while (index != -1)
{
if (name.Length &gt;= index + 2)
{
first = name.Substring(index + 1, 1);
string start = name.Substring(0, index);
string end = name.Substring(index + 2, name.Length - index - 2);
name = start + first.ToUpper() + end;

index = name.IndexOf("_");
}
}

name = name.Replace("_", "");

return name;
}
}
}

完成上面代码,这个工具的核心功能基本就完成了。

源码下载地址:点击下载

 

[转载]一种精确从文本中提取URL的思路及实现 - 方亮的专栏 - 博客频道 - CSDN.NET

mikel阅读(981)

[转载]一种精确从文本中提取URL的思路及实现 – 方亮的专栏 – 博客频道 – CSDN.NET.

在今年三四月份,我接受了一个需求:从文本中提取URL。这样的需求,可能算是非常小众的需求了。大概只有QQ、飞信、阿里旺旺等之类的即时通讯软 件存在这样的需求。在研究这个之前,我测试了这些软件这块功能,发现它们这块的功能还是非常弱的。这类软件往往也是恶意URL传播的媒介,如果不能准确识 别出URL,相应的URL安全检测也无从谈起。而且网上也有很多使用正则表达式的方法,可是我看了下,方法简单但是不够精确,对于要求不高的情况可以胜 任,但是如果“坏人”想绕过这种提取也是很方便的。(转载请指明出处)下面也是我在公司内部做的一次分享的内容:

URL介绍

全称:Uniform Resource Locators。

  • 最常见“最”标准的URL
例子:
http://www.g.cn/
衍生出浏览器可以接受的URL(在地址栏输入的URL首先会被浏览器截获,浏览器可更具其对URL的理解进行相关容错)
协议后对斜杠无要求
http:www.g.cn
http:\www.g.cn
http:\\/\www.g.cn
……
目前主流IM对最常见“最”标准的URL的识别没有问题,但是对衍生出来的URL都是无法正确识别的。
  • 比较常见但是“不标准”(无协议头)URL
例子:
无协议头,无二级域名
例子:g.cn
无协议头,有二级域名www
例子:www.g.cn
无协议头,有二级域名,但是不是www
例子:mp3.g.cn
目前国内主流IM对URL的判别上,在没有协议头(http://等)时,寻找有没有“www.”,如果存在“www.”,则认为其后是URL。
  • 比较少见的URL
例子:
格式省略或者特殊的URL
顶级域名后包含“点”
www.g.cn.(同www.g.cn)
部分省略
www.g.cn.?wd=3(同www.g.cn./?wd=3、www.g.cn/?wd=3)
包含用户名和密码的URL
密码不为空
username:password@www.g.cn
密码为空
username:@www.g.cn
目前国内主流IM对这类URL判断是不准确的,如上例只能识别为www.g.cn
  • 比较特殊的URL
例子:
完全没有分隔符的
g.cnclick this
可以识别为g.cn,但是国内IM都不会去这么识别
比较难以归类的
mailto:@g.cn
以mailto协议标准,这个URL不符合RFC规定,因为mailto:后面@之前应该有“用户名”
以http或者ftp协议标准,这个URL是合法的,因为这个URL中用户名位mailto,密码为空。
囧啊!惊恐
看一下国内一些IM的表现:
  • URL标准定义
定义于RFC1738,详细请见http://tools.ietf.org/html/rfc1738
具有相似的格式(ftp,http,https,wais,nntp……)
<scheme> ://<user>:<password>@<host>:<port>/<url-path>
“<user>:<password>@”, “:<password>”,“:<port>”,和“/<url-path>” 是可选的。
“<user>:<password>@”可以是“<user>@”(不需要密码),也可以是“<user>:@”(密码为空)。
形式多样的(mailto,news)
形式太多样,定义宽松
一些其他特殊协议(afs……)
要么不用了,要么这份RFC没给出定义,要么很少用。
  • 格式相似的协议的URL Scheme的BNF范式
HTTP(用来指定互联网资源)
http://<host>:<port>/<path>?<searchpart>
gopher (用来指定互联网资源,已经很少用了)
gopher://<host>:<port>/<gopher-path>
nntp(网络新闻传输协议)
nntp://<host>:<port>/<newsgroup-name>/<article-number>
telnet(Internet远程登陆服务的标准协议和主要方式)
telnet://<user>:<password>@<host>:<port>/
wais(广域信息查询系统)
wais://<host>:<port>/<database> wais://<host>:<port>/<database>?<search> wais://<host>:<port>/<database>/<wtype>/<wpath>
  • 格式相似的协议的URL Scheme的BNF范式
file(描述文件资源)
file://<host>/<path>
prospero(Be used to designate resources that are accessed via the Prospero Directory Servic)
prospero://<host>:<port>/<hsoname>;<field>=<value>
  • 形式多样的协议的URL Scheme的BNF范式
news
news:<newsgroup-name>
news:<message-id>
例子:
news:msnews.microsoft.com
mailto
mailto:<rfc822-addr-spec>
例子:
mailto:1@g.cn
  • 一些其他特殊协议
afs Andrew File System global file names.
mid Message identifiers for electronic mail.
cid Content identifiers for MIME body parts.
nfs Network File System (NFS) file names.
tn3270 Interactive 3270 emulation sessions.
mailserver Access to data available from mail servers.
z39.50 Access to ANSI Z39.50 services.
  • URL的RFC文档对提取URL的帮助
提供了所有的协议头,帮助准确找到URL起始位置
提供了http、ftp等协议名
定义了各种URL的范式,为准确得提取URL有很大的帮助
如ali-inc.com中的ali-inc部分要求“-”是可选的,且在存在“-”时,要求其左右存在数字或者字母。
如user name和password部分(username:password@g.cn)如果出现“:”、 “@”或“/”时要加密,这将帮助寻找到URL的起始位置(@user:pass@g.cn提取的URL是user:pass@g.cn)。
  • 基于以上问题,可以有种折中方案:将URL范式和现在已知的toplabel结合,构成一个新的范式。以下是RFC文档中BNF范式结合实际问题被修改成的正则表达式:
  1. ((((ftp:|https:|http:)([\Q/\\E])*)|())(((%[0-9a-fA-F][0-9a-fA-F])|([a-zA-Z0-9])|([\Q$-_.+!*‘(),;?&=\E]))+(:((%[0-9a-fA-F][0-9a-fA-F])|([a-zA-Z0-9])|([\Q$-_.+!*’(),;?&=\E]))*)?@)?(((((([a-zA-Z0-9]){1}([a-zA-Z0-9\-])*([a-zA-Z0-9]{1}))|([a-zA-Z0-9]))\.)+(biz|com|edu|gov|info|int|mil|name|net|org|pro|aero|cat|coop|jobs|museum|travel|arpa|root|mobi|post|tel|asia|geo|kid|mail|sco|web|xxx|nato|example|invalid|test|bitnet|csnet|onion|uucp|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))|([0-9]{1,3}(\.[0-9]{1,3}){3}))(\:([0-9]+))?(([\Q/\\E])+((((%[0-9a-fA-F][0-9a-fA-F])|([a-zA-Z0-9])|([\Q$-_.+\!*‘(),;:@&=\E]))*)(([\Q/\\E])*((%[0-9a-fA-F]{2})|([a-zA-Z0-9])|([\Q$-_.+\!*’(),;:@&=\E]))*)*)(\?((%[0-9a-fA-F]{2})|([a-zA-Z0-9])|([\Q$-_.+!*'(),;:@&=<>#”{}[] ^`~|\/\E]))*)*)*)
看着是不是特别复杂?是的!这将导致效率非常低下。(这是很久前一个做实验的版本,不能保证其准确性)利用这个正则表达式中我们可以发现很多域名,这些域名都是我从某款安全辅助软件的二进制文件中扒下来了大笑。可能有人会认为这个正则效率的瓶颈在匹配这些域名上,其实不是,我做个实验,主要的瓶颈在domainlabel(就是.com等之前的那部分)上,所以优化比较困难。而且这个正则还没考虑一些特殊问题,比如将“。”识别成”.”。
  • 域名
  1. biz|com|edu|gov|info|int|mil|name|net|org|pro|aero|cat|coop|jobs|museum|travel|arpa|root|mobi|post|tel|asia|geo|kid|mail|sco|web|xxx|nato|example|invalid|test|bitnet|csnet|onion|uucp|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw
这个域名还是比较全的,我没有全部测试,只是大致看了下,毕竟是别人总结的,不知道别人是否在里面放了“标记”信息。我曾经担心过xxx这个域名,还搜了下,发现很大大笑!。还有请仔细看,这些域名中没有数字,这为我之后的设计提出了一种思路。
  • 国内IM对URL提取的处理
  • 解读:
    目前对URL的提取思路基本上是先考虑是否存在协议部分(http,ftp等),如果存在协议部分,则认为此协议之后URL可以接受的部分都是URL。这 种方式存在很大的缺陷,如http://1也会被识别为一个URL。而http:g.cn则不会识别为一个完整的URL。
    对于不存在协议部分的情况,寻找www.,如果存在www.则认为此串为URL,如:www.1就会被识别为URL,而mp3.g.cn则不会识别为 URL。以mp3.g.cn和www.g.cn为例,.cn为顶级域名,g.cn为一级域名,而mp3.g.cn和www.g.cn都是二级域名。由于一 开始时,人们习惯将二级域名www.g.cn指向了一级域名g.cn,久而久之,人们就认为www.开头的URL为一级域名。我想可能这个是造成目前这种 判断URL的逻辑的原因。
  • 上述方法的优缺点
优点:
逻辑简单
效率高
缺点:
判断不准确
产生以上优缺点的原因
只是寻找http,https,ftp,file,mailto,www这几个关键词。因为关键词少,所以逻辑简单也高效。有利有弊,因为关键词少,也一定程度上影响了URL判断的不准确性。
  • 再次对URL进行分析和思考
常见的URL分类:
IP形式: 192.168.1.1,10.20.11.1
Domain形式:g.cn、www.g.cn,mp3.g.cn
观察可以见得:IP形式的URL结构最为简单:4个小于255的数字被.分割;domain形式比较复杂,但是它们有共性:都具有顶级域名.cn。
提取URL的大致思路
通过以上的规律,可以发现,使用顶级域名来识别URL比使用协议或者www二级域名的方式要准确,同时辅助以IP鉴别,以求达到最大覆盖。
对前人做了总结和分析后,以下是我设计的提取逻辑

  • 提取URL的基本逻辑
  • 案例:
原始文字 提取结果
这个是g.cn g.cng.co
g.com/index.htm? g.com/index.htm?s=g.cn
s=g.cn1.2.3.456 1.2.3.45
g.cn和g.com g.cn
g.com
1.2.3.4.5 1.2.3.4
2.3.4.5
以上是设计的相关逻辑
  • 以下是我写的一个demo的提取结果
  • 效率
最差URL形式 最优URL形式
URL形式 g.com.12.com.12.com.…… g.com/1111111111111……
遍历次数 约 (n+1)*n/2(O(n^2)) 约n(O(1))
URL长度 最差耗时(ms/10,000次查找) 最优耗时(ms/100,000次查找)
200 1529 400
410 3921 578
810 11703 953
1620 39463 1719
2450 82980 2453
3270 143151 3219
4300 266341 4141
  • 优化
目前的代码还是存在很多可以优化的地方:
因为我采用的递归调用,所以在最差情况下,执行效率大概是26ms一条,所以可以将递归改成循环来解决。
我使用的是C++类写的,如果改成C并_fastcall调用约定也会快些。
目前这个逻辑大致思路是从头到尾走一遍(不包括回溯),提取出以domain形式和IP形式的URL。在此之前,我设计成以domain形式从头到尾检测一次,和以IP形式从头到尾检测一次,然后综合两个结果的方法,这样的设计会比我目前这样的设计快一个数量级(已测)。

[转载]根据url提取网站域名的方法小结 - JeffWong - 博客园

mikel阅读(894)

[转载]根据url提取网站域名的方法小结 – JeffWong – 博客园.

前言:最近使用到了他人总结的一个基础类库。查看了下源码,发现String帮助类的一个辅助方法不是很严谨,重构之。

1、原来程序的写法

public static string GetDomainName(string url)
  {
      Regex reg = new Regex(@"http(s)?://([\w-]+\.)+[\w-]+/?");
      string result = reg.Match(url, 0).Value;
      if (result.IndexOf("http://") > -1)
      {
          result = result.Replace("http://", string.Empty);
      }
      else if (result.IndexOf("https://") > -1)
      {
          result = result.Replace("https://", string.Empty);
      }
      return result.Replace("/", string.Empty);
  }

2、改进方案

上面的写法,我认为不严谨的地方有两处:a、没有区分部分字符串的大小写(虽然通常传入的url都是小写http(s)开头的,使用起来问题不大);b、参数没有考虑为null的情况。下面给出我的几种解决方法,个人认为相对而言比较简洁严谨一些。

(1)正则改进

  按照原来代码的写法,正则表达式是先提取出形如 http://www.cnblogs.com/ 的形式的字符串,然后再处理字符串。字符串替换和hard coding看起来会比较多,而且,毫无疑问,上面代码中的正则提取的字符串稍显冗余。我的改进如下:

public static string GetDomainName(string url)
     {
         if (url == null)
         {
             throw new Exception("输入的url为空");
         }
         Regex reg = new Regex(@"(?<=[://])([\w-]+\.)+[\w-]+/?", RegexOptions.IgnoreCase);
         return reg.Match(url, 0).Value.Replace("/", string.Empty);
     }

应该说这是比较忠实于源代码的一种实现。
【UPDATE】:根据文章后面布袋和尚说不得大师的指点,再改进一下正则表达式,这样对于正常的url路径或其他类型的路径都可以进行验证匹配了。代码如下:

public static string GetDomainName(string url)
     {
         if (url == null)
         {
             throw new Exception("输入的url为空");
         }
         Regex reg = new Regex(@"(?<=://)([\w-]+\.)+[\w-]+(?<=/?)");
         return reg.Match(url, 0).Value.Replace("/", string.Empty);
     }

(2)直接拼接字符串

  拼接字符串在实际开发中可以做很多事情,简单的域名提取自然不在话下。我们分析一下输入的url,发现很显著也很重要的一个特征就是通过斜线(/)来分割字符串,每一个分隔后的字符串分别表示不同的属性,如对应的协议名称,域名,站点名,页面名称等等。具体分割拼接提取的方法如下:

public static string GetDomainName(string url)
   {
        if (url == null)
       {
           throw new Exception("输入的url为空");
       }
       string result = string.Empty;
       string[] strArr = url.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
       foreach (string item in strArr)
       {
           if (string.Compare("http:", item.ToLower()) == 0)
           {
               continue;
           }
           else if (string.Compare("https:", item.ToLower()) == 0)
           {
               continue;
           }
           result = item;
           break;
       }
       return result;
   }

严格来说,这个是比较“笨”的方法,但是通俗易懂。

(3)通过一个HttpRequest对象获取它的Url的Host

  平时我们都是通过HttpRequest对象获取它的Url的Host来获取网站域名,现在只有一个字符串参数url,很显然,我们会想到构造一个HttpRequest对象,然后按步就班即可。具体方法如下:

public static string GetDomainName(string url)
{
    string result = null;
    try
    {
        HttpRequest request = new HttpRequest(string.Empty, url, string.Empty);
        result = request.Url.Host;
    }
    catch (Exception ex)
    {
        throw new Exception(string.Format("当前输入的URL:{0},发生异常:{1}", url, ex.Message));
    }
    return result;
}

这个应该算是另辟蹊径的一种解决方案,可是必需要引用System.Web dll,作为基础类库,应该越少引用越好。

结语:到这里,根据url提取host的常规方法基本重构完成,没有过分考虑效率和性能,不知哪种会更快一点。期待您更好的方法和意见。

[转载]mvp模式的android项目构建 - 小change - 博客园

mikel阅读(1070)

[转载]mvp模式的android项目构建 – 小change – 博客园.

多日未回博客园,风萧萧兮易水寒。

话说上一次发表随笔已是去年,而且看看当时关于Android视频方面的记录也只写了开篇就自动阉割成了太监,究其缘由已不堪回首。

太监终究还是太监,没必要再为它续弦。

笔锋一转,近日有看几本Android应用方面优化和技巧方面的书,便觉得又该在此处记录下了。有一本专门讲技巧的书还不错,《50 Android Hacks》:50个android开发诀窍。

其中有一篇是讲MVP(Model-View-Presenter)模式的,也就是模型-视图-主导器(书中翻译为此)。

我大概理解了下该篇内容,以几乎可以和HELLO WORLD 齐名的登陆功能为需求,写了个Demo,以明了其中的缘由,如果以下内容有出错的地方,还望指正,不吝赐教。

【一笔带过】MVP模式与大名鼎鼎的MVC模式似乎就只有最后一个字母的差别,也就在于主导器代替了控制器的地位。所谓主导器,也就是扮演着主导一切(模型与视图)的地位。

【先看看我们熟悉的】模型层,通常是数据结构,我们业务需要用到的一些数据封装。这里会稍稍有些不同,我们同时封装了数据行为,即是该类具有我们实际业务逻辑的要实现的方法。–一小波代码正在袭来…

package com.change.mvpdemo.modle;

/**
 * MVP模式的m(模型)层。
 * 登陆状态,登陆的实际逻辑实现它去完成。
 * @author Change
 *
 */
public interface ILoginStatus extends IStatus{
    public static final int STATUS_VERIFY_FAIL = -1;//验证失败
    public static final int STATUS_LOGIN_FAIL = -2;//登陆失败
    public static final int STATUS_LOGIN_SUCCESS = 0;//登陆成功
    public static final int STATUS_LOGIN_ING = 1;//登陆中
    /**
     * 登陆行为
     * @param account
     * @param psw
     * @return 状态码
     */
    public void login(String account,String psw,IStatusCallback callback);
}

【简单说说】我有个接口IStatus暂时来说没什么内容,或许可以放一些共有的状态,比如响应成功或者失败。然后数据模型以状态的形式存在,因为我有个不怎么成熟的想法就是数据往往都是根据业务状态在修改它本身的内容。然后就一个login()方法,里面的参数有请求和响应。好吧,是时候去实现它了–》

package com.change.mvpdemo.modle.impl;

import android.os.AsyncTask;
import android.text.TextUtils;

import com.change.mvpdemo.modle.ILoginStatus;
import com.change.mvpdemo.modle.IStatusCallback;

/**
 * 实现类,真正的数据访问在这里。
 * 
 * @author Change
 */
public class LoginStatus implements ILoginStatus {
    private int status = ILoginStatus.STATUS_LOGIN_ING;
    private String msg = "";

    @Override
    public void login(final String account, final String psw,
            final IStatusCallback callback) {
        new AsyncTask<String, Void, ILoginStatus>() {
            @Override
            protected ILoginStatus doInBackground(String... arg0) {
                if (varify(account, psw)) {
                    try {//模拟网络请求耗时处理
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if ("Change".equals(account) && "123".equals(psw)) {
                        status = ILoginStatus.STATUS_LOGIN_SUCCESS;
                        msg = "登陆成功";
                    } else {
                        status = ILoginStatus.STATUS_LOGIN_FAIL;
                        msg = "登陆失败";
                    }
                }
                return LoginStatus.this;
            }

            @Override
            protected void onPreExecute() {
                callback.onStatus(LoginStatus.this);
                
            }

            @Override
            protected void onPostExecute(ILoginStatus result) {
                callback.onStatus(result);
            }
        }.execute();

    }

    /**
     * 本地校验
     * 
     * @param account
     * @param psw
     * @return
     */
    private boolean varify(String account, String psw) {
        if (TextUtils.isEmpty(account)) {
            status = ILoginStatus.STATUS_VERIFY_FAIL;
            msg = "用户名不能为空!";
            return false;
        }
        if (TextUtils.isEmpty(psw)) {
            status = ILoginStatus.STATUS_VERIFY_FAIL;
            msg = "密码不能为空!";
            return false;
        }
        return true;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    

}

【简单说说】这是我的数据模型,我有状态(status),要反馈给视图的信息(msg)。里面有本地验证方法varify()和提交服务器(此处只是模拟个耗时)login()方法的实现。根据login方法的反馈修改自身并回调。我们该关心是谁在实现这个回调了–》

【再看看我们熟悉的】视图层,万恶的视图永远都占据着用户的眼球,好吧,所有后台偷偷摸摸完成的东西都要拿出来晾晾了。–》

package com.change.mvpdemo.view;

/**
 * MVP模式的V(视图)层
 * 这是一个抽象的登陆视图,里面都是一些界面动作,想要执行这些动作的界面都会去实现它。
 * @author Change
 *
 */
public interface ILoginView extends IView{
    /**
     * 弹出提示信息。
     */
    public void showMsg(String msg);
    /**
     * 成功登陆跳转主页。
     */
    public void moveToMain();
    /**
     * 加载中,万恶的菊花。
     */
    public void showLoadding();
    /**
     * 隐藏菊花。
     */
    public void hideLoadding();
}

【简单说说】无论是亲切的hello world(主页)跳转,还是万恶的菊花,还是该死的提示。ILoginView一手包办。来吧,让UI交互来的更猛烈些吧。

【我们最为熟悉的】activity君隆重登场,它会毫不留情的实现ILoginView。并且将UI蹂躏的七零八落。

package com.change.mvpdemo.view.impl;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.change.mvpdemo.R;
import com.change.mvpdemo.presenter.LoginPersenter;
import com.change.mvpdemo.view.ILoginView;

/**
 * 我的的activity,实现view抽象类,获得动作。
 * 
 * @author Change
 * 
 */
public class LoginActivity extends Activity implements ILoginView,
        OnClickListener {
    private ProgressDialog dialog;
    private EditText etAccount, etPsw;
    private Button btnLogin;
    private LoginPersenter mPersenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        mPersenter = new LoginPersenter();
        mPersenter.setLoginPersenterView(this);
        initViews();
    }

    @Override
    public void showMsg(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void moveToMain() {
        Intent toMain = new Intent(this, MainActivity.class);
        startActivity(toMain);
    }

    @Override
    public void showLoadding() {
        dialog.show();
    }

    @Override
    public void hideLoadding() {
        dialog.cancel();
    }

    @Override
    public void initViews() {
        dialog = new ProgressDialog(this);
        dialog.setMessage("加载中。。。");
        etAccount = (EditText) findViewById(R.id.et_account);
        etPsw = (EditText) findViewById(R.id.et_psw);
        btnLogin = (Button) findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0) {
        switch (arg0.getId()) {
        case R.id.btn_login:
            mPersenter.didLoginSuccess(etAccount.getText().toString(), etPsw
                    .getText().toString());
            break;

        default:
            break;
        }
    }

}

【主导器君隆重登场】我想诸位都已经看到这厮了-_-|||–>mPersenter,没错,这厮便是我的主导器君。好的,它来了–》

package com.change.mvpdemo.presenter;

import com.change.mvpdemo.modle.ILoginStatus;
import com.change.mvpdemo.modle.IStatus;
import com.change.mvpdemo.modle.IStatusCallback;
import com.change.mvpdemo.modle.impl.LoginStatus;
import com.change.mvpdemo.view.ILoginView;

/**
 * MVP模式中的P(主导器),它负责主导所有的模型和视图。
 * 
 * @author Change
 * 
 */
public class LoginPersenter {
    private ILoginView mLoginView;// 持有视图对象
    private ILoginStatus mStatus;// 持有模型

    public LoginPersenter() {
        mStatus = new LoginStatus();
    }

    public void setLoginPersenterView(ILoginView _loginView) {
        this.mLoginView = _loginView;
    }

    public ILoginView getLoginPersenterView() {
        return mLoginView;
    }

    public void didLoginSuccess(String account, String psw) {
        mStatus = new LoginStatus();
        mStatus.login(account, psw, new IStatusCallback() {

            @Override
            public void onStatus(IStatus status) {
                LoginStatus s = (LoginStatus) status;
                switch (s.getStatus()) {
                case ILoginStatus.STATUS_VERIFY_FAIL:// 验证失败
                case ILoginStatus.STATUS_LOGIN_FAIL:// 登陆失败
                    mLoginView.hideLoadding();
                    mLoginView.showMsg(s.getMsg());
                    break;
                case ILoginStatus.STATUS_LOGIN_ING:// 登陆中
                    mLoginView.showLoadding();
                    break;
                case ILoginStatus.STATUS_LOGIN_SUCCESS:// 登陆成功
                    mLoginView.hideLoadding();
                    mLoginView.moveToMain();
                    break;
                default:
                    break;
                }
            }
        });
    }
}

【其实它也不过如此】主导器中我就写了个核心的方法didLoginSuccess(),它主导模型与视图,让视图在根据模型的变化而做出正确的响应。

【该做个总结性的发言了】莱迪森,剑特闷-_-||

【MVP模式有什么用】其实回顾下模式的各个模块,似乎解耦的很干脆,是的,我们的视图和模型被瓦解出来了,这个时候我们的TDD(测试驱动开发)就能更好的实施了,我们能在后台未完成的时候很快捷的模拟出自己想要的数据,从而让我们进度不被滞后。

【世界杯要决赛了,买什么?】
 

把故事讲好 真的很难!

mikel阅读(1003)

给女儿讲懂现金流老鼠赛跑的故事真的很难!让5周岁的孩子能够听懂,还要不理解、不乏味、听得进去真的很难!

开始作为铺垫,先试着给他讲了胡萝卜和驴的故事,看看她的理解能力。

当讲到农夫想到办法坐在驴背上拿根杆子钓个胡萝卜,放在驴前面,驴盯着胡萝卜往前走,张嘴想吃胡萝卜又吃不着的时候,她咯咯笑起来,看来是听懂了。

出乎意料的是故事讲完了,她居然说了一句:那驴真傻!傻驴!

讲故事的我很有成就感!看来老鼠赛跑的故事,她应该也能听懂,懂不懂无所谓了,财商不是一天两天能够培养出来的。

然后,给她讲了老鼠赛跑的现金流游戏的故事,她听着听着睡着了,不知道效果怎么样?!

上周日买了大富翁的游戏棋, 回家跟她玩儿,尽管她100、1000、10000还不知道怎么念,但是她居然说是不是跟那两只老鼠赛跑的故事那样玩儿啊?!让我很惊讶!

孩子就像一张白纸,你给她讲什么样的故事,要教育她什么,潜移默化的她会去想,尽管不能完全理解,但是她会有个模糊的概念,当有什么东西触发了她,她会反应出来。

故事是最容易让人接受的方式,也是最好的传播方式。

把故事讲好真的很难!让人们理解并接受更是难上加难!

最好的化难为简的方式就是换位思考,然后找到痛点,认真的为听众讲一个浅显易懂的故事。