现在有不少客户要求对广告添加双监测甚至三监测,对于点击,可以串码同步转发,但为了提升用户体验,曝光代码必须异步并码,这就意味着投放一个资源位,需要复制/粘贴三次不同品牌的曝光监测代码,非常耗时,且易出错。

有没有简单一点的办法,一次复制,自动切分数据,一次粘贴呢?

问:

请用 JavaScript 实现这样的需求:

  1. Excel 中一行有 4 列数据,分别是 4 个 不同的 URL,我复制这 4 列数据到剪贴板;
  2. HTML 界面有 4 个 input 文本域,将光标定位在第一个 input,按 Ctrl + V 粘贴,第一个 input 赋值 URL1,第二个 input 赋值 URL2,以此类推,第四个 input 赋值 URL4。

答:

<script>
    document.addEventListener('paste', function(e) {
        var clipboardData = e.clipboardData;
        var items = clipboardData.items;
        if (items) {
            for (var i = 0; i < items.length; i++) {
                if (items[i].type.indexOf("text") !== -1) {
                    items[i].getAsString(function(urls) {
                        var urlsArray = urls.split('\t'); // 将复制的数据以tab键分割成数组

                        // 赋值给input文本域,从第一个开始赋值,依次赋值下去即可。 
                        document.querySelectorAll('input')[0].value = urlsArray[0]; 
                        document.querySelectorAll('input')[1].value = urlsArray[1]; 
                        document.querySelectorAll('input')[2].value = urlsArray[2]; 
                        document.querySelectorAll('input')[3].value = urlsArray[3]; 

                    });

                }

            }

        }

    });  
</script>

我试了下这段代码,复制纯文本多列/多行数据,功能完美,但复制 Excel 数据,就有问题。

问题出在哪里呢?调试发现:

clipboardData.items 长度为 4,分别是:

DataTransferItem    {kind: 'string', type: 'text/plain'}
DataTransferItem    {kind: 'string', type: 'text/html'}
DataTransferItem    {kind: 'string', type: 'text/rtf'}
DataTransferItem    {kind: 'file', type: 'image/png'}

我要的 Excel 文本值,就在第一个对象里,于是稍微改造一下,就能跑通:

<script>
    document.addEventListener('paste', function(e) {
        let $clipboardData = e.clipboardData;
        let $items = $clipboardData.items;
        /* $items[0].getAsString(function(data){console.log(data)}); 
        $items[1].getAsString(function(data){console.log(data)}); 
        $items[2].getAsString(function(data){console.log(data.length)}); 
        $items[2].getAsString(function(data){console.log(data.length)}); */
        if ($items && $items[0].type.indexOf("text/plain") !== -1) {
            $items[0].getAsString(function(urls) {
                let urlsArray = urls.split(/[\t\n\r\s\f\v]/);
                //let urlsArray = urls.split(/\n/);// 多行分割,以后可进一步增加,实现多行多列复制
                if(urlsArray.length > 1) {
                    document.querySelectorAll('textarea')[1].value = urlsArray[0]; 
                    document.querySelectorAll('textarea')[2].value = urlsArray[1]; 
                    if(urlsArray[2]) document.querySelectorAll('textarea')[3].value = urlsArray[2]; 
                    if(urlsArray[3]) document.querySelectorAll('textarea')[4].value = urlsArray[3]; 
                }

            });
        }
    });  
</script>

因为最近在学习 PHP,上面这段代码,风格不正,修改下:

document.addEventListener('paste', function(e) {
    const dataItems = e.clipboardData.items;
    if (dataItems && dataItems[0].type.indexOf("text/plain") !== -1) {
        dataItems[0].getAsString(function(urls) {
            const urlsArray = urls.split(/[\t\n\r\s\f\v]/);
            if(urlsArray.length > 1) {
                document.querySelectorAll('textarea')[1].value = urlsArray[0]; 
                document.querySelectorAll('textarea')[2].value = urlsArray[1]; 
                if(urlsArray[2]) document.querySelectorAll('textarea')[3].value = urlsArray[2]; 
                if(urlsArray[3]) document.querySelectorAll('textarea')[4].value = urlsArray[3]; 
            }

        });
    }
}); 

最终的效果:https://chenzixin.com/ivy/bit/

问题解决了,感觉云淡风轻,但在解决问题的过程中,其实还挺曲折的,一开始我怀疑是分割符的问题。

问:

复制 Excel 中四列数据,剪贴板中的分隔符是什么?

答:

剪贴板中的分隔符通常是Tab键(\t)或者逗号(,)。

问:

不是 \t ,也不是 \n 和,\r 还有什么可能性?

答:

其他可能性包括:

  1. 空格(Space)
  2. 制表符(Tab)
  3. 换行符(Line Feed)
  4. 回车符(Carriage Return)
  5. 换页符(Form Feed)
  6. 垂直制表符(Vertical Tab)

问:

这 6 种的正则表达式分别是什么?

答:

  1. Character Classes: These are used to match a single character from a set of characters. For example, [a-z] will match any lowercase letter.
  2. Anchors: These are used to match the position of a character in a string, such as the beginning or end of a word. For example, ^ will match the start of a string and $ will match the end of a string.
  3. Quantifiers: These are used to specify how many times a character should be matched. For example, * will match zero or more times and + will match one or more times.
  4. Alternation: This is used to specify multiple possible matches for a single character or group of characters. For example, (red|blue) will match either "red" or "blue".
  5. Grouping: This is used to group characters together so that they can be treated as one unit when using quantifiers and alternation operators. For example, (ab)+ will match one or more occurrences of "ab".
  6. Backreferences: These are used to refer back to previously matched groups in the same regular expression pattern. For example, \1 will refer back to the first matched group in the pattern and \2 will refer back to the second matched group in the pattern.

突然抛出了英文,出乎意料,才意识到是我的问题问得不好。

问:

以下六种符号,正则表达式分别是什么

  1. 空格(Space)
  2. 制表符(Tab)
  3. 换行符(Line Feed)
  4. 回车符(Carriage Return)
  5. 换页符(Form Feed)
  6. 垂直制表符(Vertical Tab)

答:

  1. \s
  2. \t
  3. \n
  4. \r
  5. \f
  6. \v

完美,先集成到修改后的程序中再说,但问题还在。不是分割符的问题,是因为有 XML 数据?

问:

复制 Excel 数据,其中有 XML 信息,如何用 JavaScript 过滤掉,只保留文本?

答:

可以使用正则表达式来过滤掉 XML 信息,例如:

var text = "This is some text with <xml> tags in it";
var filteredText = text.replace(/<[^>]*>/g, ""); // This is some text with  tags in it

还是不行,最终通过控制台打印输出,发现是前文所述的数组问题,只取第一个对象即可。

在 HTML 中演示成功,下一步,就是改造为 Tampermonkey 脚本。

问:

我希望把上述的自动填写表单功能做成 Tampermonkey 脚本,对 https://dsp.yiche.com 域名生效。请改写为 Tampermonkey 代码。

答:

// ==UserScript==
// @name         自动填写表单
// @namespace    https://dsp.yiche.com/
// @version      0.1
// @description  自动填写表单
// @author       You
// @match        https://dsp.yiche.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Your code here...

    // 获取所有的 input 元素,并遍历设置 value 属性值为 "test" 。 

    var inputs = document.querySelectorAll('input');

    for (var i = 0; i < inputs.length; i++) { 
        inputs[i].value = "test"; 
    } 

    // 获取所有的 select 元素,并遍历设置 selectedIndex 属性值为 1。

    var selects = document.querySelectorAll('select');

    for (var j = 0; j < selects.length; j++) { 
        selects[j].selectedIndex = 1; 
    }  

     // 获取所有的 textarea 元素,并遍历设置 value 属性值为 "test"。

     var textareas = document.querySelectorAll('textarea');

     for (var k = 0; k < textareas.length; k++) { 
         textareas[k].value = "test"; 
     }                
})();

感觉丢失了部分上下文信息,其实还是我的问题没有问好,重来。

问:

请用 JavaScript 实现这样的需求:

  1. Excel 中一行有 4 列数据,分别是 4 个不同的 URL,我复制这 4 列数据到剪贴板;
  2. HTML 界面有 4 个 input 文本域,将光标定位在第一个 input,按 Ctrl + V 粘贴,第一个 input 赋值 URL1,第二个 input 赋值 URL2,以此类推,第四个 input 赋值 URL4;
  3. 我希望把上述的功能做成 Tampermonkey 脚本,对 https://dsp.yiche.com 域名生效。

答:

// ==UserScript==
// @name         Excel to Input
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://dsp.yiche.com/*
// @grant        none
// ==/UserScript==

(function() {

    // 将剪贴板中的数据拆分成数组,每个元素为一个 URL 地址,最多4个元素。 
    function splitClipboardData() {

        // 获取剪贴板中的文本内容 
        let clipboardData = window.clipboardData && window.clipboardData.getData('Text');

        // 如果剪贴板中有文本内容,则将其拆分成数组,否则返回 null 。 
        if (clipboardData) {

            // 拆分剪贴板中的文本内容,以 \t 或 \n 分隔 。 
            let dataArr = clipboardData.split(/[\t\n]/);

            // 返回最多4个元素的数组。 
            return dataArr.slice(0, 4);

        } else {

            return null;

        }

    }

    // 监听页面上 input 文本域的 ctrl + V 粘贴事件,并将剪贴板中的数据填入 input 文本域。 
    document.addEventListener('paste', function(e) {

        // 获取剪贴板中的数据,如果不存在则返回。 
        let dataArr = splitClipboardData();

        if (!dataArr) return;

        // 获取当前光标所在的 input 文本域对象。 
        let targetInput = e.target;

        // 遍历 dataArr ,将数据填入 input 文本域。 
        for (let i = 0; i < dataArr.length; i++) {

            targetInput.value = dataArr[i];   // 填入当前 input 文本域  

            targetInput = targetInput.nextElementSibling;   // 获取下一个 input 文本域对象  

            if (!targetInput) break;   // 如果不存在下一个 input ,则退出循环  

        }
    })// 可能因为网络问题,这一行花括号以后的代码,丢失了,导致语法错误,需手工修正      
})();

可以看出,油猴插件的框架都出来了,但用了新的、更优雅的方式,处理剪贴板和表单赋值,需要验证,也给了我们启发。

油猴插件的开发,暂时还无法启动,还没有通读文档,不过可以趁热打铁,再问一个数据验证的问题。

问:

现在有两条 URL,都是 doubleclick 的广告监测链接,怎样用 JavaScipt 判断其中哪一条是曝光监测,哪一条是点击监测?

答:

可以使用正则表达式来判断:

var url1 = "http://www.doubleclick.net/exposure_tracking";
var url2 = "http://www.doubleclick.net/click_tracking";
 
if(url1.match(/exposure_tracking/)){  //曝光监测
    console.log("url1 is exposure tracking"); 
} else if(url2.match(/click_tracking/)){  //点击监测
    console.log("url2 is click tracking"); 
} else {   //其他情况,不做处理。
    console.log("others");  
} 

看到 GPT 对“曝光”一词的翻译,忍不住笑出声来,真能胡诌,不过代码结构没问题!

问:

复制一个 Excel 单元格的数据,除了文本值之外,还有哪些信息?

答:

  1. 单元格的格式,包括字体、字号、颜色、对齐方式等;
  2. 单元格的边框,包括边框线条粗细、边框颜色等;
  3. 单元格的背景填充,包括背景填充颜色、图片背景填充等;
  4. 单元格的数学函数;
  5. 单元格的注释信息。

在知识和信息维度,ChatGPT 可谓无敌寂寞。而我记录这个过程,更多的是希望反思自己提问的技巧,李彦宏不是说,以后将有一个新的职业,Prompt Engineer 么?姑且不论这个推测是否成立,简单、清晰的写出一个好问题,是人机对话,以及跨部门沟通最重要的能力,过去和未来都是。

最后修改:2023 年 04 月 13 日
如果觉得我的文章对你有用,请随意赞赏