踏破铁鞋无觅处,得来全不费工夫--删除文本多余空行ClipboardFormatter

从网上拷一些文章,总是有很多很多很多....的空行,

如下图(CRLF就是换行符\r\n),怎么去掉它们呢?

一般方法就是贴到文本编辑器中,

然后查找替换,查找替换,查找替换....

周而复始,不厌其烦....

一定有更好的办法,

想象中...

如果有什么办法,让电脑自动完成这件事,那该多好啊!

于是就有了本文的想法:

------写一个程序自动删除拷贝的文本里多余的空行.

(电脑的过剩的计算资源不用白不用)

动手吧

要实现的程序是这样工作的:

首先得取得剪切板的内容(不要问剪切板是什么?),

然后查找重复的关键字(\r\n\r\n),然后替换成一个(\r\n),

最后把替换完的文本内容,写回剪切板中,

...后面,会考虑写成托盘程序,

能自启动

写代码了^_^

实现一个剪切板的类Clipboard,主要用于取得剪切板内容,和设置剪切板内容

//仅用于个人测试学习用途,作者不对使用本软件与代码产生的任何结果负责
//作者: wisepragma
//主页:http://blog.csdn.net/wisepragma

#pragma once
#include <Windows.h>
#include <tchar.h>
class Clipboard
{
private:
        TCHAR*          m_pBuffer;//动态内存,用于存剪切板文本拷贝
        int             m_bufSize;//拷贝的缓冲大小
        UINT            m_ClipFormat;//剪切板文本的格式,根据程序自动选择
        HANDLE          m_hclip;//剪切板句柄,实际是剪切板内存指针
private:
        void destroy()
        {
                if(m_pBuffer!=NULL)
                {
                        delete[]m_pBuffer;
                        m_pBuffer=NULL;
                }
        }
public:
        Clipboard()
        {
                m_pBuffer=NULL;
                m_ClipFormat=(  sizeof(TCHAR)==sizeof(WCHAR) )?CF_UNICODETEXT:CF_TEXT;//根据程序版本,设置剪切板的文本类型
        }
        ~Clipboard()
        {
                destroy();
        }
        UINT count()
        {
                m_bufSize=0;
                if(OpenClipboard(NULL))
                {
                        if(IsClipboardFormatAvailable(m_ClipFormat))
                        {
                                HANDLE hclip=GetClipboardData(m_ClipFormat);

                                TCHAR* pClipBuffer=static_cast<TCHAR*>(GlobalLock(hclip) );
                                m_bufSize=lstrlen(pClipBuffer);
                                GlobalUnlock(hclip);
                                CloseClipboard();
                        }
                }
                return m_bufSize;
        }
        TCHAR* gettxt()
        {
                destroy();//释放动态内存,避免多次调用下内存泄漏
                if(OpenClipboard(NULL))
                {
                        if(IsClipboardFormatAvailable(m_ClipFormat))
                        {
                                HANDLE hclip=GetClipboardData(m_ClipFormat);
                                TCHAR* pClipBuffer=static_cast<TCHAR*>(GlobalLock(hclip) );//锁定剪切板,取得剪切板字符串地址
                                if(m_pBuffer!=NULL) delete[]m_pBuffer;
                                m_bufSize=lstrlen(pClipBuffer);//并计算此字符串长度
                                m_pBuffer=new TCHAR[m_bufSize+1];//申请动态内存,加1个空间,装NULL结尾符
                                memcpy(m_pBuffer,pClipBuffer,m_bufSize*sizeof(TCHAR));//拷出剪切板,bugfixed:memcpy()以字节计数不是字
                                m_pBuffer[m_bufSize]=TEXT(‘\0‘);//组装成一个以NULL结尾的字符串
                                GlobalUnlock(hclip);//解锁剪切板,锁与解锁间动作要快
                                CloseClipboard();
                        }
                }
                return m_pBuffer;
        }
        bool settxt(TCHAR* str)
        {
                HANDLE hClip;
                if(m_hclip!=NULL) GlobalFree( m_hclip);
                if( OpenClipboard(NULL) )
                {
                        EmptyClipboard();//写入前一定要清空
                        int len=lstrlen(str);
                        m_hclip=GlobalAlloc(GMEM_MOVEABLE,(len+1)*sizeof(TCHAR));//BUBFIXED:GlobalAlloc()参数2以字节为单位
                        TCHAR *pClipBuffer=static_cast<TCHAR*>(GlobalLock(m_hclip));
                        lstrcpy(pClipBuffer,str);
                        //写入剪切板
                        GlobalUnlock(m_hclip);
                        hClip=SetClipboardData(m_ClipFormat,m_hclip);
                        //成功反回指向剪切板的句柄,失败返回NULL
                        CloseClipboard();
                }
                return (hClip!=NULL);//写入成功
        }
};

接下来,要来怎么处理文本字符串

这个问题好像很简单,不过我想得太复杂了...

举例来说有一个字符串是这样定义的

CString s="今天今天今天今天今天今天我有所思在远道,一日不见兮,我心悄悄今天今天今天今天今天今天今天今天今天今天今天今天常言道:天道酬勤,静以修身,俭以养德.今天今天今天事事通晓皆道理,人情达练即文章今天今天今天今天今天今天";

我们要把其中所有的,多个连续的"今天"替换成一个"今天",于是我想到从字串开头逐个字遍历,当找到"今天"后,以关键字"今天"的长度遍历,直到找到非关键字"今天"记录下关键字串的开头与结尾,重复个数等信息,然后再逐个字遍历,直到字串的结尾(描述好长)

struct node
{
        UINT iDifferentStart;
        UINT nSame;
        UINT iSameStart;
        node *next;
};

class KeyWordReplacer
{
private:
        node *m_head;//单向链表记录下索引等信息
        CString *m_sString;
        CString m_sKeyWord4Search;
        CString m_sKeyWord4Replace;

        CString m_sFormatText;
        UINT m_nString;
        UINT m_nKeyWord;

public:
        ~KeyWordReplacer()
        {
                destory();
        }
        void destory()
        {
                if(NULL!=m_head)
                {
                        while(m_head!=NULL)
                        {
                                node *idx=m_head;
                                m_head=m_head->next;
                                delete idx;
                        }
                }
                m_head=NULL;
        }
        KeyWordReplacer( CString  *sTxt, TCHAR *pSearchkeyWord,TCHAR *pReplaceKeyWord=NULL)
        {
                //循环的工作原理:从m_sString中查找与关键字m_sKeyWord4Search相同的,记录相同的个数
                //然后在返回的索引下查找与关键字m_sKeyWord4Search不同的
                //通过单向链表记录下索引等信息
                m_sString=sTxt;
                m_sKeyWord4Search=pSearchkeyWord;
                m_sKeyWord4Replace=pReplaceKeyWord;
                m_nString=m_sString->GetLength();
                m_nKeyWord=m_sKeyWord4Search.GetLength();
                m_head=NULL;

                UINT ix=m_sString->Find(m_sKeyWord4Search);//ix用于从m_sString查找关键字m_sKeyWord4Search
                if( ix!=-1 )//没找到返回-1,找到返回第一个关键字下标
                {
                        m_head=new node;
                        m_head->next=NULL;
                        m_head->nSame=0; //用于累计相同关键字的个数
                        if(ix==0) m_head->iDifferentStart=-1;//在开头找到关键字, m_head->iDifferentStart以-1表示
                        else m_head->iDifferentStart=0;//在开头没找到关键字, m_head->iDifferentStart以0表示
                        m_head->iSameStart=ix;// m_head->iSameStart即iDifferentEnd

                        node *inx=m_head;
                        do{
                                UINT iz=ix;//iz用于记录查找非关键字退出循环时刻,最后的索引
                                for(UINT iy=ix; iy<=m_nString-m_nKeyWord; iy+=m_nKeyWord)//iy用于从m_sString查找非m_sKeyWord4Search关键字
                                {
                                        iz=iy;

                                        if( m_sString->Mid(iy,m_nKeyWord)==m_sKeyWord4Search )
                                        {
                                                inx->nSame++; //累计相同关键字的个数
                                                if(inx->nSame==1) inx->iSameStart=iy;//第一次找到关键字即iDifferentEnd
                                                //_tprintf(_T("//[%d],%d,%s\n"),iy,inx->nSame,m_sString->Mid(iy,m_nKeyWord));
                                        }
                                        else
                                        {     //链表有两种生长方式(new node<==m_head 和 m_head==>new node) //本程序使用此方式m_head==>new node
                                                inx->next=new node;
                                                inx=inx->next;
                                                inx->nSame=0;//初始化为0,以便下一次累计相同关键字的个数
                                                inx->next=NULL;//重要!!!这是遍历结束的标志
                                                inx->iSameStart=-1;//在结尾没找到关键字,iSameStart=-1表示
                                                inx->iDifferentStart=iy;//链表记录非关键字的开始
                                                //_tprintf(_T("\n"));
                                                break;//找到不同的即立退出
                                        }
                                }
                                ix=m_sString->Find(m_sKeyWord4Search,iz);//查找关键字

                        }while( ix!=-1 &&  ix<m_nString-m_nKeyWord);

                }

        }
        CString &Replace(TCHAR *pReplaceKeyWord=NULL)
        {
                if( NULL!=pReplaceKeyWord ) m_sKeyWord4Replace=pReplaceKeyWord;
                if(NULL!=m_head)
                {
                        node *idx=m_head;
                        while(idx!=NULL )
                        {
                                _tprintf(_T("//[iDifferentStart:%d],iSameStart:%d,[nSame:%d],%s\n"),idx->iDifferentStart,idx->iSameStart, idx->nSame,m_sString->Mid(idx->iDifferentStart) );

                                if( idx->iSameStart == -1 )
                                {
                                        m_sFormatText+=m_sString->Mid( idx->iDifferentStart);
                                        //m_sFormatText+=m_sKeyWord4Replace;//注释掉末尾不加入替换关键字
                                        _tprintf(_T("//....[sDifferent:%s]\n"),m_sString->Mid( idx->iDifferentStart) );
                                }
                                else
                                {
                                        if(idx->iDifferentStart != -1)
                                        {
                                                m_sFormatText+=m_sString->Mid(idx->iDifferentStart, idx->iSameStart - idx->iDifferentStart);
                                                m_sFormatText+=m_sKeyWord4Replace;
                                                _tprintf(_T("//....[sDifferent:%s]\n"), m_sString->Mid(idx->iDifferentStart, idx->iSameStart - idx->iDifferentStart) );
                                        }
                                }
                                idx=idx->next;
                        }
                }
                _tprintf(_T("字串:%s\n查找:%s\n替换成:%s\n结果:%s\n"),*m_sString,m_sKeyWord4Search,m_sKeyWord4Replace,m_sFormatText);

                return m_sFormatText;
        }
        TCHAR *getText()
        {
                return m_sFormatText.GetBuffer( m_sFormatText.GetLength() );
        }
};

int _tmain()
{
        setlocale(LC_CTYPE,"CHS");//加上#include<locale.h>,[加上#include <tchar.h>]让_tprintf()在ANSI,UNICODE下都能支持中文

        //CString s="我是菩提树上菩提花,冷眼看人世千年尘沙,你流连树下,回眸那一刹,天地间只剩你眉眼如画,长亭十里忆你风袖迎晨霞,清酒一壶醉里弄琴琶,长亭十里忆你薄衫牵骏马,梅雨一帘多少相思话";
        //CString s="今天今天今天今天今天今天今天今天今天";
        //CString s=_T("但是今天今天今天今天今天它真写今天今天今天些什么着");
        //CString s="今天今天今天今天今天今天我有所思在远道,一日不见兮,我心悄悄今天今天今天今天今天今天今天今天今天今天今天今天常言道:天道酬勤,静以修身,俭以养德.今天今天今天事事通晓皆道理,人情达练即文章今天今天今天今天今天今天";

        Clipboard brd;
        CString sClipBoard=brd.gettxt();
        KeyWordReplacer crlf(&sClipBoard,_T("\r\n") );
        crlf.Replace(_T("\r\n"));
        //KeyWordReplacer crlf(&sClipBoard,_T("今天"),_T("▓") );
        if(NULL!=crlf.getText() )
        {

                brd.settxt( crlf.getText() );
        }
        else _tprintf(_T("没有找到和替换\n"));

        getchar();
}

下面就来测试

结果是这样的

但是当我把一个4MB左右的文本拿来作试验的时候,发现了一个问题

那就是---效率实在太低了!!!

辗转反侧,上下求索,没找到好的办法.....

突然有一天,眼前一亮,CString 不是有一个Replace()函数吗

然后就着NOTEPAD2替换着文本的换行

然后简化了代码:(有点黯然神伤)

bool bRemoveAllCRLF=false;
Clipboard brd;
_tprintf(_T("...正在读取剪切板...\n"));
CString sClipBoard=brd.gettxt();
_tprintf(_T("...正在查找并替换多余空行...\n"));
int nReplace=0;
bool bKeyWordFound=false;
do{
	   if(bRemoveAllCRLF)
	   {
		   nReplace=sClipBoard.Replace(_T("\r\n"),_T(""));
	   }
	   else
	   {
		   nReplace=sClipBoard.Replace(_T("\r\n\r\n"),_T("\r\n"));
	   }
	   if( nReplace>0 )bKeyWordFound=true;
}while( nReplace>0);//重复替换,直到替换个数为0
if(bKeyWordFound )
{
		_tprintf(_T("...正在写入剪切板...\n"));
		bool bSucceed=brd.settxt( sClipBoard.GetBuffer(sClipBoard.GetLength() ) );
	  if(bSucceed) _tprintf(_T("...删除剪切板多余空行成功...\n"));
}

虽然是重复地进行查找替换,但是它的效率不是一般地高,差距啊

接着把KeyWordReplacer类改进为KeyWordRemover

//仅用于个人测试学习用途,作者不对使用本软件与代码产生的任何结果负责
//作者: wisepragma
//主页:http://blog.csdn.net/wisepragma
#pragma once
#include <windows.h>
#include <tchar.h>
class KeyWordRemover
{
private:
        CString m_sText;
public:
	bool remove( TCHAR  *sTxt, TCHAR *pskeyWord,bool bRemoveAll=false)
	{                

                CString s1keyword(pskeyWord);//单重关键字
                CString s2keyword=s1keyword+pskeyWord;//双重关键字
                m_sText=sTxt;
                int nReplace=0;
                bool bKeyWordFound=false;
                do{
                        if(bRemoveAll)
                        {
                                nReplace=m_sText.Replace(s1keyword,_T(""));    //s1keyword单重关键字 替换成 空即删除关键字 , 这个比下面的耗时
                        }
                        else
                        {
                                nReplace=m_sText.Replace(s2keyword,s1keyword);        //双重关键字 替换成 单重关键字 即 缩减关键字
                        }
                        if( nReplace>0 )bKeyWordFound=true;
                }while( nReplace>0);//直到替换个数为0

                return bKeyWordFound;
	}
        TCHAR *gettxt()
        {
                return m_sText.GetBuffer( m_sText.GetLength() );
        }
};

搞定了!

做成WINDOWS托盘图标式软件是这个样子的

代码与软件

ClipboardFormatter[bin]

ClipboardFormatter[src]

踏破铁鞋无觅处,得来全不费工夫--删除文本多余空行ClipboardFormatter,布布扣,bubuko.com

时间: 2024-08-09 15:50:48

踏破铁鞋无觅处,得来全不费工夫--删除文本多余空行ClipboardFormatter的相关文章

去除文本多余空行

1.读取文件: OpenFileDialog dialog=new OpenFileDialog(); dialog.InitialDirectory = Application.StartupPath; dialog.Filter = "All Files|*.*|text file(*.txt)|*.txt"; dialog.RestoreDirectory = true; if (dialog.ShowDialog() == DialogResult.OK) { string f

C++ - 删除文本的最后一行 代码(C++)

删除文本的最后一行 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 读取文本的每行("\n"), 存储入数组vector<string>, 输出时, 少输出最后一行, 即可. 代码: /* * main.cpp * * Created on: 2014.06.08 * Author: Spike */ /*vs 2012*/ #include <windows.h> #include <fstream&g

kindeditor文本编辑器删除文本中图片路径出错

string[] imgname; MODEL.Strategy modelMenu = bllMenu.GetModel(int.Parse(strId)); imgname = getPicUrl.getPicUrls(modelMenu.SContent).Split('|'); foreach (string c in imgname) { ImageHelper.DeleteImg(HttpContext.Current.Server.MapPath(c)); } kindeditor

js在一个可编辑的div光标处插入图片或者文本(兼容ie,火狐等浏览器)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Typ

新浪笔试题之删除文本中词频最小的所有字符串

时间:2014.06.04 地点:基地二楼 -------------------------------------------------------------------------------- 一.题目 题目大概是这样纸的,一个文本文件,里面有好多字符串,要求删除在整个文本中出现频率最少的字符串,如果这个最小值对应的字符串有很多,则都删除,结果是输出一个文本,保留下来的字符串用 '\t' 符号分割. ------------------------------------------

sed删除文本第一个匹配行

源文本如下,要求删除第一个为happy-123456的行. ----------------------------- aaaaaaa happy-123456 bbbbbb asdasawe happy-123456 dsafsdfsd sagasdfasd happy-123456 ------------------------------ 目标文本: ----------------------------- aaaaaaa bbbbbb asdasawe happy-123456 ds

[代码审计]phpshe开源商城后台两处任意文件删除至getshell

0x00 背景 这套系统审了很久了,前台审不出个所以然来.前台的限制做的很死. 入库的数据都是经过mysql_real_escape_string,htmlspecialchars的处理. 二次注入没找到,逻辑漏洞也没找到.抛开实际利用来说,简单讲讲两个任意文件删除漏洞,在拿到后台之后的getshell方法. 0x01 phpshe程序简介 phpshe是一个开源商城程序,程序在前台入库的地方都用了pe_dbhold函数(mysql_real_escape_string,htmlspecialc

git同步远程已删除的分支和删除本地多余的分支

使用 git branch -a 可以查看本地分支和远程分支情况 但远程分支(红色部分)删除后,发现本地并没有同步过来. 一. 同步本地的远程分支 查看本地分支和追踪情况: git remote show origin 可以发现红框中的分支是远程分支已被删除的分支,根据提示可以使用 git remote prune 来同步删除这些分支. 运行命令: git remote prune origin 再次查看分支情况: 发现红色部分的远程分支已经同步,远程删除的分支,本地也已经不见了. 二. 删除本

git 同步远程已删除的分支和删除本地多余的分支

使用git branch -a可以查看本地分支和远程分支情况 但远程分支(红色部分)删除后,发现本地并没有同步过来. 一. 同步本地的远程分支 查看本地分支和追踪情况: git remote show origin 可以发现红框中的分支是远程分支已被删除的分支,根据提示可以使用git remote prune 来同步删除这些分支. 运行命令: git remote prune origin 二. 删除本地多余分支 git branch -D feature/chatfix 啦啦啦 原文地址:ht