受别人python作品启发,顺便练一下c语言编程
用到知识点:调用curl库访问http请求,pcre正则查找字符串,json解析翻译结果
先安装3个库
sudo apt-get install libcurl4-openssl-dev
sudo apt-get install libpcre3-dev
sudo apt-get install libjson-c-dev
经过反复调试终于通了,感觉比python代码多了好多
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <pcre.h>
#include <unistd.h>
#include <json-c/json.h>
// 全局变量 32位
char g_ig[48] = {0};
char g_tokenkey[128] = {0};
char g_key[24] = {0};
char g_token[64] = {0};
char g_url[256] = {0};
struct MemoryStruct
{
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if (ptr == NULL)
{
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
printf(" memory (%s)\n", mem->memory);
return realsize;
}
int translate(const char *word, char *translated_text)
{
struct MemoryStruct chunk;
chunk.memory = malloc(1);
chunk.size = 0;
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
// 初始化libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
// 这里需要构造请求URL和数据
// 示例 URL
sprintf(g_url, "https://cn.bing.com/ttranslatev3?isVertical=1&IID=translator.5027&IG=%s", g_ig); // 示例 IG
const char *url = g_url;
printf("url: %s\n", url);
// 添加一个HTTP头部
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
if (headers == NULL)
{
fprintf(stderr, "curl_slist_append() failed.\n");
curl_easy_cleanup(curl);
return 1;
}
// 添加另一个HTTP头部
headers = curl_slist_append(headers, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36");
if (headers == NULL)
{
fprintf(stderr, "curl_slist_append() failed.\n");
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return 1;
}
// 设置HTTP头部到CURL句柄
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_setopt() failed: %s\n", curl_easy_strerror(res));
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return 1;
}
CURL *hCurl = curl_easy_init();
curl_easy_setopt(hCurl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(hCurl, CURLOPT_SSL_VERIFYHOST, 0L);
// 使用 POST 请求
curl_easy_setopt(curl, CURLOPT_URL, url);
char post_data[512] = {0};
sprintf(post_data, "fromLang=zh-Hans&text=%s&to=en-GB&key=%s&token=%s&tryFetchingGenderDebiasedTranslations=true", word, g_key, g_token); // 这里填写你的POST数据
printf("post_data: %s\n", post_data);
// curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); // 这里填写你的POST数据
// 设置写入回调
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
// 执行请求
res = curl_easy_perform(curl);
// 检查请求是否成功
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
else
{
// 解析 JSON 响应
struct json_object *parsed_json = json_tokener_parse(chunk.memory);
if (parsed_json == NULL)
{
printf("Error parsing JSON\n");
free(chunk.memory);
return 3;
}
// 确认解析的对象类型是否是数组
if (json_object_is_type(parsed_json, json_type_array))
{
// printf("解析成功,这是一个JSON数组\n");
// 获取数组的长度
int len = json_object_array_length(parsed_json);
// printf("数组长度: %d\n", len);
// 遍历数组
for (int i = 0; i < len; i++)
{
struct json_object *obj = json_object_array_get_idx(parsed_json, i);
if (obj)
{
// 获取键值对
struct json_object *name = json_object_object_get(obj, "translations");
if (name && json_object_is_type(name, json_type_array))
{
int len = json_object_array_length(name);
printf("translations 数组长度: %d\n", len);
struct json_object *obj = json_object_array_get_idx(name, 0);
if (obj)
{
struct json_object *name = json_object_object_get(obj, "text");
if (name && json_object_is_type(name, json_type_string))
{
sprintf(translated_text, "%s", json_object_get_string(name));
printf("name : %s\n", translated_text);
}
}
}
}
}
}
else
{
printf("解析成功,但不是一个JSON数组\n");
}
// 释放资源
free(chunk.memory);
return 0; // 返回翻译后的文本
}
// 清理CURL列表和句柄
curl_slist_free_all(headers);
// 清理
curl_easy_cleanup(curl);
}
curl_global_cleanup();
free(chunk.memory);
return 2;
}
int gethttptofile()
{
// printf("Hello, gethttptofile!\n");
// 1、curl全局初始化,初始化libcurl库(只能调用一次)
// CURL_GLOBAL_ALL尽可能初始化一切(除了CURL_GLOBAL_ACK_EINTR)
// CURL_GLOBAL_WIN32表示libcurl会初始化winsock库,如果失败则无法使用socket,windows系统专用
// CURL_GLOBAL_SSL初始化SSL,(不初始化可能无法使用https)
// CURL_GLOBAL_DEFAULT初始WIN32和SSL
// CURL_GLOBAL_ACK_EINTR设置此标志后,curl将在连接或等待数据时确认EINTR条件。否则,curl会等待直到完全超时。(在7.30.0中添加)
CURLcode init = curl_global_init(CURL_GLOBAL_ALL);
if (init != CURLE_OK)
{
printf("curl全局初始化失败!\n");
exit(1);
}
// 2、初始化curl,返回CURL句柄
CURL *curl = (struct CURL *)curl_easy_init();
if (curl == NULL)
{
printf("初始化CURL失败!\n");
exit(1);
}
// 3、设置option,各种curl参数的
curl_easy_setopt(curl, CURLOPT_URL, "https://cn.bing.com/translator");
// 设置保存位置,使用临时文件或保存到fopen中
FILE *file = fopen("biying.htm", "w");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
// 各option
// 1.CURLOPT_URL
// 设置访问URL
// 2.CURLOPT_WRITEFUNCTION,CURLOPT_WRITEDATA
// 通过设定一个回调函数,执行libcurl在接受到数据后用户想进行的操作,通常函数多做数据保存的功能,如处理下载文件。CURLOPT_WRITEDATA 用于表明CURLOPT_WRITEFUNCTION函数中的stream指针的来源,说白了就是设定回调函数的第四个参数的数据类型。回调函数原型为:size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
// 3.CURLOPT_HEADERFUNCTION,CURLOPT_HEADERDATA
// 通过设定一个回调函数,执行libcurl在接受到http头数据后用户想进行的操作。CURLOPT_WRITEDATA 传递指针给libcurl,该指针表明CURLOPT_HEADERFUNCTION 函数的stream指针的来源。回调函数原型为 size_t function( void *ptr, size_t size,size_t nmemb, void *stream);
// 4.CURLOPT_READFUNCTION CURLOPT_READDATA
// libCurl需要读取数据传递给远程主机时将调用CURLOPT_READFUNCTION指定的函数,函数原型是:size_t function(void *ptr, size_t size, size_t nmemb,void *stream). CURLOPT_READDATA 表明CURLOPT_READFUNCTION函数原型中的stream指针来源,说白了就是设定回调函数的第四个参数的数据类型。
// 5.CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTION,CURLOPT_PROGRESSDATA
// 跟数据传输进度相关的参数。CURLOPT_PROGRESSFUNCTION 指定的函数正常情况下每秒被libcurl调用一次,为了使CURLOPT_PROGRESSFUNCTION被调 用,CURLOPT_NOPROGRESS必须被设置为false,CURLOPT_PROGRESSDATA指定的参数将作为 CURLOPT_PROGRESSFUNCTION指定函数的第一个参数
// 6.CURLOPT_TIMEOUT,CURLOPT_CONNECTIONTIMEOUT:
// CURLOPT_TIMEOUT 用于设置传输时间,CURLOPT_CONNECTIONTIMEOUT 设置连接等待时间
// 7.CURLOPT_FOLLOWLOCATION
// 设置重定位URL
// CURLOPT_RANGE: CURLOPT_RESUME_FROM:
// 断点续传相关设置。CURLOPT_RANGE 指定char *参数传递给libcurl,用于指明http域的RANGE头域,例如:
// 表示头500个字节:bytes=0-499
// 表示第二个500字节:bytes=500-999
// 表示最后500个字节:bytes=-500
// 表示500字节以后的范围:bytes=500-
// 第一个和最后一个字节:bytes=0-0,-1
// 同时指定几个范围:bytes=500-600,601-999
// CURLOPT_RESUME_FROM 传递一个long参数给libcurl,指定你希望开始传递的偏移量。
// 8.CURLOPT_UPLOAD:
// 如果第三个参数被设置为1的话,就是让libcurl做好上传的准备。如果传输协议是http的话,uoload就是发送put。
// 9. CURLOPT_SSL_VERIFYPEER:
// 第三个参数的缺省值为1.该函数多用于设定curl忽略对网站证书的检查(不管忽略不忽略,curl都是检查的)。
// 10.CURLOPT_VERBOSE
// 相当厉害的一个参数,可以向控制台(默认)输出curl接受和发送的数据,输出流可以重定向。
// 11.CURLOPT_HTTPGET
// 将curl向服务器交互数据的方式改变为get
// 4、执行curl的各种操作的请求
CURLcode curLcode = curl_easy_perform(curl);
if (curLcode != CURLE_OK)
{
printf("curl请求失败:%d!\n", curLcode);
exit(1);
}
// perform错误码说明:
// 1.CURLE_OK
// 任务完成一切都好
// 2.CURLE_UNSUPPORTED_PROTOCOL
// 不支持的协议,由URL的头部指定
// 3.CURLE_COULDNT_CONNECT
// 不能连接到remote 主机或者代理
// 4.CURLE_REMOTE_ACCESS_DENIED
// 访问被拒绝
// 5.CURLE_HTTP_RETURNED_ERROR
// Http返回错误
// 6.CURLE_READ_ERROR
// 读本地文件错误
// 5、读取请求响应的信息
long totalTime;
curLcode = curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &totalTime);
if (curLcode != CURLE_OK)
{
printf("curl获取信息失败:%d!\n", curLcode);
}
printf("CURLINFO_TOTAL_TIME:%ld!\n", totalTime);
// getinfo参数
// CURLINFO_EFFECTIVE_URL - 最后一个有效的URL地址
// CURLINFO_HTTP_CODE - 最后一个收到的HTTP代码
// CURLINFO_FILETIME - 远程获取文档的时间,如果无法获取,则返回值为“-1”
// CURLINFO_TOTAL_TIME - 最后一次传输所消耗的时间
// CURLINFO_NAMELOOKUP_TIME - 名称解析所消耗的时间
// CURLINFO_CONNECT_TIME - 建立连接所消耗的时间
// CURLINFO_PRETRANSFER_TIME - 从建立连接到准备传输所使用的时间
// CURLINFO_STARTTRANSFER_TIME - 从建立连接到传输开始所使用的时间
// CURLINFO_REDIRECT_TIME - 在事务传输开始前重定向所使用的时间
// CURLINFO_SIZE_UPLOAD - 以字节为单位返回上传数据量的总值
// CURLINFO_SIZE_DOWNLOAD - 以字节为单位返回下载数据量的总值
// CURLINFO_SPEED_DOWNLOAD - 平均下载速度
// CURLINFO_SPEED_UPLOAD - 平均上传速度
// CURLINFO_HEADER_SIZE - header部分的大小
// CURLINFO_HEADER_OUT - 发送请求的字符串
// CURLINFO_REQUEST_SIZE - 在HTTP请求中有问题的请求的大小
// CURLINFO_SSL_VERIFYRESULT - 通过设置CURLOPT_SSL_VERIFYPEER返回的SSL证书验证请求的结果
// CURLINFO_CONTENT_LENGTH_DOWNLOAD - 从Content-Length: field中读取的下载内容长度
// CURLINFO_CONTENT_LENGTH_UPLOAD - 上传内容大小的说明
// CURLINFO_CONTENT_TYPE - 下载内容的Content-Type:值,NULL表示服务器没有发送有效的Content-Type:header
// 6、清理curl句柄
curl_easy_cleanup(curl);
// 7、清理全局配置(只能调用一次)
curl_global_cleanup();
fclose(file);
return 0;
}
int getIg(const char *subject, const char *pattern, char *result, int lenIgnorance)
{
// const char *subject = "This is a test string.IG:\"1F3128B9E5D4487288669FC943AF4D1A\"";
// const char *pattern = "IG:\"(.*?)\"";
const char *error;
int erroffset;
pcre *re;
pcre_extra *extra;
int ovector[48] = {0};
// 编译正则表达式
re = pcre_compile(pattern, 0, &error, &erroffset, NULL);
if (re == NULL)
{
printf("PCRE compilation failed at offset %d: %s\n", erroffset, error);
return 1;
}
// 使用额外的编译选项
extra = pcre_study(re, 0, &error);
if (error != NULL)
{
printf("PCRE study failed: %s\n", error);
pcre_free(re);
return 1;
}
// 执行正则表达式匹配
int rc = pcre_exec(re, extra, subject, strlen(subject), 0, 0, ovector, 48);
if (rc < 0)
{
if (rc == PCRE_ERROR_NOMATCH)
{
printf("No match found.\n");
}
else
{
printf("Matching error: %d\n", rc);
}
}
else
{
printf("Match found starting at offset %d %.*s\n", ovector[0], ovector[1] - ovector[0] - lenIgnorance - 1, subject + ovector[0] + lenIgnorance);
strncpy(result, subject + ovector[0] + lenIgnorance, ovector[1] - ovector[0] - lenIgnorance - 1);
}
// 释放资源
pcre_free(re);
if (extra != NULL)
pcre_free(extra);
return 0;
}
/*
* 功能:获取token
* */
int getToken()
{
FILE *file = fopen("biying.htm", "r");
// 8、操作文件内容
// 流指针移动到末尾
fseek(file, 0, SEEK_END);
// 返回当前流指针位置
const long i = ftell(file);
printf("文件长度:%ld!\n", i);
// 计算完毕记得把流指针归位
rewind(file);
// 申请一块能装下整个文件内容的内存区域
char *a = (char *)malloc(i);
// fgets(a, i+1,file);
fread(a, 1, i, file);
// printf("当前文件内容:%s \n", a);
getIg(a, "IG:\"(.*?)\"", g_ig, 4);
printf("ig: %d %s\n", strlen(g_ig), g_ig);
getIg(a, "params_AbusePreventionHelper = (.*?);", g_tokenkey, 32);
printf("g_tokenkey: %d %s\n", strlen(g_tokenkey), g_tokenkey);
int d = strstr(g_tokenkey, ",") - g_tokenkey;
// printf("key: %d %.*s\n", d, d, g_tokenkey);
sprintf(g_key, "%.*s", d, g_tokenkey);
printf("g_key: %s\n", g_key);
int t = strstr(g_tokenkey, "\",") - strstr(g_tokenkey, ",\"") - 2;
// strncpy(g_token, g_tokenkey + d + 2, t);
// printf("g_token: d=%d t=%d\n", d + 2, t);
sprintf(g_token, "%.*s", t, g_tokenkey + d + 2);
g_token[t] = '\0';
printf("g_token: %d %s\n", strlen(g_token), g_token);
// 记得释放申请的内存区域
free(a);
// 关闭临时文件
fclose(file);
return 0;
}
int main(int argc, char *argv[])
{
char *word = "待翻译的文本";
if (argc > 1)
{
word = argv[1];
}
char result_trans[256] = {0};
int ret = gethttptofile();
ret = getToken();
ret = translate(word, result_trans);
// if (0 == ret)
// {
// printf("翻译结果: %s\n", result_trans);
//}
return 0;
}
然后编译运行
gcc -o bingtrans bingtrans.c -lcurl -lpcre -ljson-c
./bingtrans 可持续发展
顺利翻译出来 sustainable development
然后顺便也记录一下原python代码,差距好大,下次如果是要搞这类小工具还是python更简洁
import requests
import re
import json
def trans(word):
flg=re.search(r'[\u4e00-\u9f5a]',word)
#en-GB 英文
#zh-Hans 中文,
from_word,to_word =('zh-Hans','en-GB') if flg else ('en-GB','zh-Hans')
uri = 'https://cn.bing.com/translator'
gi = requests.get(uri).text
ig = re.search(r'IG:"(.*?)"', gi).group(1)
token = re.search(r'params_AbusePreventionHelper = (.*?);', gi).group(1)
tokens = token.replace("[", "")
js = tokens.split(',')
t = js[1][1:33]
url = 'https://cn.bing.com/ttranslatev3?isVertical=1&IG={}&IID=translator.5027'.format(ig)
data = {
'fromLang': from_word,
'text': word,
'to': to_word,
'token': t,
'key': js[0],
'tryFetchingGenderDebiasedTranslations': 'true'
}
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36'
}
try:
response = requests.post(url, data=data, headers=headers)
translations = response.json()[0]['translations']
translated_text = translations[0]['text']
return translated_text
except:
return "翻译失败"
if __name__ == '__main__':
word="别无选择唯有前行"
result=trans(word)
print(result)
#原文字:你说你,想要逃,剩下空心要不要
#示例结果:You said that you want to escape, and you want to leave the hollow or not
#新文字: There is no choice but to move forward