LaTeX 写作的两个辅助工具:统计中文字数和关闭Acrobat中的PDF文档

LaTeX word count LaTex字数统计工具,解压后从CMD中打开该路径,运行如下代码: perl texcount.pl -v -sum=1 -1 trb.tex > count.txt trb.tex替换成自己的文档名。 需要先安装perl 立即下载

LaTeX 没有像 Word 那样自带中文字数统计功能,加上 LaTeX 源文件中有许多控制字符,不能通过文件大小获知其中有多少汉字。为此我用C写了一个统计中文字数的小工具,名为 cwc ,即 chinese word counter。这个程序只有 count_files() 函数使用了 Windows API,稍作修改就能移植到 Linux/Unix 下。


#include <stdio.h>
#include <wchar.h>
#include <windows.h>
int total = 0; // total chinese characters

// UNICODE version word counter
void word_count_u(FILE* pf)
{
    int w = 0, b = 2;
    wint_t c;

    while((c = getwc(pf)) != WEOF) {
        b += 2;         // byte count
        if (c > 127) {  // 中文字符
            w++;        // char count
        }
    }
   
    printf("%10d /t %10d/n", w, b);
    total += w;
}

// word counter
void word_count(const char* file)
{
    int w = 0, b = 0;
    int c;
    int unicode = 0;
   
    FILE *pf = fopen(file, "rb");
    if (NULL == pf) {
        return;
    }
    printf ("%20s : ", file);
    
    // 判断是否为 UNICODE 文件
    if ((c = getc(pf)) == 0xff) {
        int cc;
        if ((cc = getc(pf)) == 0xfe) {
            unicode = 1;
            printf("UNICODE");
            word_count_u(pf);
        }
        else {
            fseek(pf, 0, SEEK_SET);
        }
    }
    else {
        ungetc(c, pf);
    }
   
    if (!unicode) {
        printf("       ");
        while((c = getc(pf)) != EOF) {
            b++; // byte count
            if (c > 127) { // 中文字符
                w++; // char count
                b++; // 每个中文字符占两字节
                if ((c = getc(pf)) == EOF)
                    break;
            }
        }
   
        printf("%10d /t %10d/n", w, b);
        total += w;
    }
    fclose(pf);
}

void count_files(const char* file)
{
    WIN32_FIND_DATA FindFileData;
    HANDLE hFind = FindFirstFile(file, &FindFileData);

    if (INVALID_HANDLE_VALUE == hFind) {
        fprintf(stderr, "Can't find %s/n", file);
        return ;
    }

    do {
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
            continue;
        }
        if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // do nothing
        }
        else {
            word_count(FindFileData.cFileName);
        }
    } while (FindNextFile(hFind, &FindFileData));

    FindClose(hFind);
}

int main(int argc, char* argv[])
{
    if (1 == argc) {
        // default: count all .tex and .txt files in current dir
        count_files("*.tex");
        count_files("*.txt");
    }
    else {
        // get filenames from command line arguments
        while (--argc > 0) {
            count_files(argv[argc]);
        }
    }
    printf("  Total : %d", total);
    return 0;
}


另外一个常见的问题是,用 dvipdfm 生成 PDF 文件时,经常忘了在 Acrobat 中关闭这个文件,而导致出现以下错误提示:

E:/Projects/SlideWindowReport>dvipdfm SlideWindow

SlideWindow.dvi -> SlideWindow.pdf

Unable to open SlideWindow.pdf


Output file removed.

为此我写了一个专门用来关闭 Acrobat 中的 PDF 文件的小工具,名为 closepdf,原理是通过 DDE 告诉 Acrobat 关闭某个 PDF 文件。这个小工具的灵感来自 WinEdt 的自动关闭功能(我跟踪它的宏代码得知如何用 DDE 控制 Acrobat),代码改自 MSDN 的一篇文章。我完全不懂 DDE,不过这不妨碍程序的正常工作:)

有了这个小工具,我就可以写一个 batch file 来编译生成并阅读 PDF 文件:

rem this is m.bat
latex %1
latex %1
closepdf %1.pdf
dvipdfm %1 %2 %3 %4 %5
start %1.pdf


代码如下:
// close the user specified pdf file in Acrobat Reader

// ref. Microsoft Knowledge Base Article - 279721
// HOWTO: Use Dynamic Data Exchange (DDE) with Word and Excel from Visual C++

// modified by Solstice 2004/01/2

#define WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers
#define STRICT

#include <windows.h>
#include <ddeml.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

HDDEDATA CALLBACK DdeCallback(
    UINT uType,     // Transaction type.
    UINT uFmt,      // Clipboard data format.
    HCONV hconv,    // Handle to the conversation.
    HSZ hsz1,       // Handle to a string.
    HSZ hsz2,       // Handle to a string.
    HDDEDATA hdata, // Handle to a global memory object.
    DWORD dwData1,  // Transaction-specific data.
    DWORD dwData2)  // Transaction-specific data.
{
    return 0;
}

void DDEExecute(DWORD idInst, HCONV hConv, char* szCommand)
{
    HDDEDATA hData = DdeCreateDataHandle(idInst, (LPBYTE)szCommand,
                               lstrlen(szCommand)+1, 0, NULL, CF_TEXT, 0);
    if (hData==NULL)   {
        printf("Command failed: %s/n", szCommand);
    }
    else    {
        DdeClientTransaction((LPBYTE)hData, 0xFFFFFFFF, hConv, 0L, 0,
                             XTYP_EXECUTE, TIMEOUT_ASYNC, NULL);
    }
}

void DDERequest(DWORD idInst, HCONV hConv, char* szItem, char* sDesc)
{
    HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
    HDDEDATA hData = DdeClientTransaction(NULL,0,hConv,hszItem,CF_TEXT,
                                 XTYP_REQUEST,5000 , NULL);
    if (hData == NULL)
    {
        printf("Request failed: %s/n", szItem);
    }
    else
    {
        char szResult[255];
        DdeGetData(hData, (unsigned char *)szResult, 255, 0);
        printf("%s%s/n", sDesc, szResult);
    }
}

void DDEPoke(DWORD idInst, HCONV hConv, char* szItem, char* szData)
{
    HSZ hszItem = DdeCreateStringHandle(idInst, szItem, 0);
 DdeClientTransaction((LPBYTE)szData, (DWORD)(lstrlen(szData)+1),
                          hConv, hszItem, CF_TEXT,
                          XTYP_POKE, 3000, NULL);
    DdeFreeStringHandle(idInst, hszItem);
}

int get_error(const char* filename)
{
 HANDLE hFile = CreateFile(filename,
     GENERIC_WRITE,
     FILE_SHARE_READ,
     NULL,
     OPEN_EXISTING,
     FILE_ATTRIBUTE_NORMAL,
     NULL);
   
    if (INVALID_HANDLE_VALUE == hFile) {
         return GetLastError();
    } else {
     CloseHandle(hFile);
     return 0;
    }
}

bool is_file_locked(const char* filename)
{   
 return (get_error(filename) == 32);
}

bool is_file_exists(const char* filename)
{
 return (get_error(filename) != 2);
}

int main(int argc, char* argv[])
{
    char szApp[] = "acroview";
    char szTopic[] = "control";
    char szCloseAll[] = "[CloseAllDocs()]";
    char full_file_name[MAX_PATH];
 const char* file_to_close = argv[1];
   
    if (argc == 1) {
     // close all pdf files
 } else { // close the specified file
  if (!is_file_exists(file_to_close)) {
   printf("%s doesn't exists./n", file_to_close);
   return 1;
  }
  if (is_file_locked(file_to_close)) {
   printf("%s is open, trying to close it.../n", file_to_close);
  } else {
   printf("%s is closed./n", file_to_close);
   return 0;
  }
  assert (GetFullPathName(
      file_to_close,
      sizeof(full_file_name),
      full_file_name,
      NULL
  ) > 0);
  //printf("Full name : /"%s/"/n", full_file_name);
 }
   
    //[DocOpen(""%P/%N.pdf"")]
    //[DocClose(""%P/%N.pdf"")]

    //DDE Initialization
    DWORD idInst=0;
    UINT iReturn;
    iReturn = DdeInitialize(&idInst, (PFNCALLBACK)DdeCallback,
                            APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0 );
    if (iReturn!=DMLERR_NO_ERROR)
    {
        printf("DDE Initialization Failed: 0x%04x/n", iReturn);
        Sleep(1500);
        return 0;
    }

    //DDE Connect to Server using given AppName and topic.
    HSZ hszApp, hszTopic;
    HCONV hConv;
    hszApp = DdeCreateStringHandle(idInst, szApp, 0);
    hszTopic = DdeCreateStringHandle(idInst, szTopic, 0);
    hConv = DdeConnect(idInst, hszApp, hszTopic, NULL);
    DdeFreeStringHandle(idInst, hszApp);
    DdeFreeStringHandle(idInst, hszTopic);
    if (hConv == NULL)
    {
        printf("DDE Connection Failed./n");
        Sleep(500); DdeUninitialize(idInst);
        return 0;
    }
    else
    {
     printf("DDE Connection to Acrobat Reader succeed./n");
     Sleep(50);
    }
   
    if (argc == 1) {
     // close all pdf files
     //Execute commands/requests specific to the DDE Server.
     DDEExecute(idInst, hConv, szCloseAll);
     printf("Closing all PDF documents.../n");
     Sleep(50);    
 } else { // close the specified file
  char cmd_buf[MAX_PATH + 100];
     //[DocOpen(""%P/%N.pdf"")]
     //[DocClose(""%P/%N.pdf"")]  
     printf("Closing %s /n", full_file_name);
     snprintf(cmd_buf, sizeof(cmd_buf), "[DocOpen(/"%s/")]", full_file_name);
     DDEExecute(idInst, hConv, cmd_buf);
     Sleep(50);
     snprintf(cmd_buf, sizeof(cmd_buf), "[DocClose(/"%s/")]", full_file_name);
     DDEExecute(idInst, hConv, cmd_buf);
     Sleep(50);
 }

    //DDE Disconnect and Uninitialize.
    DdeDisconnect(hConv);
    DdeUninitialize(idInst);
   
    if (argc == 1) {
     // close all pdf files
     return (0);
    }

    for (int i = 0; i < 5; ++i) {
     Sleep(100);
     if (!is_file_locked(file_to_close))
      break;
    }
    if (!is_file_locked(file_to_close)) {
     printf("%s is closed./n", file_to_close);
     return 0;
    } else {
     printf("%s is still open./n", file_to_close);
     return 1;
    }
}


⑨【从0制作自己的ros导航小车:上位机篇】04、使用gmapping建图 前面的文章已经能够实现在odom坐标系下显示小车模型和里程计数据了,本文加上激光slam必不可少的传感器雷达,先进行测试,然后直接开始建图! 阅读详情

相关推荐

Keil环境下单片机串口通信实战:如何用printf发送中文(附完整代码)

本文详细解析了在Keil开发环境下,单片机通过串口通信发送中文信息时产生乱码的根本原因及解决方案。核心在于理解并统一编码(如GB2312或UTF-8),并正确重定向printf函数。文章提供了针对STC89C52和STM32F103的完整代码示例,涵盖工程配置、编码设置、调试技巧,帮助开发者实现稳定可靠的中文串口输出。

weixin_29168675的博客 467

统计Latex格式论文字数

统计latex论文字数

qq_42230971的博客 3783

Emotion-LLaMA实战指南:从零构建多模态情感识别系统(附Python代码)

本文提供了Emotion-LLaMA多模态情感识别系统的实战指南。通过详细的步骤,指导读者从零搭建开发环境、运行本地Demo、理解模型架构,并完成数据处理与模型训练。该创新模型融合视觉、听觉与文本信息,实现更精准、接近人类理解的情感分析与推理,并附有完整的Python代码实现。

weixin_29094775的博客 416

【latex】鼓励自己写论文的小办法——每天统计写了多少字

【代码】【latex】鼓励自己写论文的小办法——每天统计写了多少字。

cicely_的博客 963

2024最新超详细无痛安装PyTorch,包括下载地址、环境配置与各种避坑指南

PyTorch更新很快,2024最新下载安装经验贴,包括anaconda+CUDA+cuDNN+PyTorch四部分的下载和安装。文章详细介绍了下载地址、环境配置、虚拟环境建立的问题,还温馨提示了各种闭坑指南。有需要的友友快过来康康!

qq_43596278的博客 11万+

基于WebGL架构的3D可视化平台—平面图导航(一)

前言 利用CampusBuilder来搭建自己的虚拟世界过程有这样一个问题:如何快速聚焦到虚拟场景的某一位置。当然我们可以创建几个按钮对应查找我们需要去的位置(参照物)并聚焦,但是按钮并不是很炫酷也不能很好的反馈给我们一些信息。接下来我们就用平面导航图来解决这一问题。 第一步:使用CampusBuilder搭建模拟场景,CampusBuilder操作简单,分分钟就可以上手。 ...

nioooom的博客 4163

overleaf统计指定.tex文件的字数(Latex文件字数统计)

overleaf统计指定.tex文件的字数(Latex文件字数统计)

weixin_43287372的博客 4931

从零构建:基于OpenCV与人体姿态分析的跌倒检测实战(附完整源码)

本文详细介绍了如何从零构建基于OpenCV与人体姿态分析的跌倒检测系统,包含完整源码与部署指南。通过MediaPipe实时检测33个人体关键点,结合多条件联合判断算法,实现高精度跌倒识别。文章还提供了性能优化技巧、常见问题解决方案以及家用与养老院两种部署方案,帮助开发者快速落地这一计算机视觉应用。

weixin_29085151的博客 240

latex pdf 统计字数

vscode。

软件工程小施同学 的专栏 3116

【调优】OpenClaw调优之模型(tokens)篇

OpenClaw用户常遇四大痛点:规则被无视、API账单暴涨、低效模型选择、记忆丢失。通过/context list命令可解析上下文组成,包括工作区配置、引导参数限制、系统提示词等关键信息。重点需关注Token消耗来源,如核心配置文件、技能工具说明等,避免静默截断。建议精简非必要内容,优化记忆机制,平衡功能与成本。该分析帮助用户减少无效操作,合理控制API支出。

海兰 991

C#实战:从零搭建Vosk离线语音转文字系统

本文手把手教你用C#构建离线语音转文字系统,基于NAudio和Vosk实现全流程开发。首先介绍环境搭建,包括NuGet包安装和中文模型配置,强调16kHz单声道音频格式的关键性。接着详细解析音频预处理转换、Vosk模型初始化及识别过程的核心代码,提供多线程优化建议和实时识别扩展思路。文章包含80%以上代码注释,从常见问题排查到性能优化技巧,完整覆盖从"Hello World"到工业级部署的关键技术点,特别适合需要开发本地化语音识别应用的C#开发者。

墨夶的博客 752
上一篇: 为 LaTeX 添加英文 TrueType 字体
下一篇: 用CodeViz绘制函数调用关系图(call graph)
陈硕
博客等级 码龄26年 1万+粉丝 144原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值