☰
UWP SemanticTextQuery 语义文本查询示例详解:用 AQS 精准定位字符串与文件属性中的命中文本
2026/9/26 2:58:10 网站建设 项目流程
  • 示例工程

【免费下载链接】Windows-universal-samples

API samples for the Universal Windows Platform.

项目地址:https://gitcode.com/gh_mirrors/wi/Windows-universal-samples
点击查看免费下载

本文围绕仓库archived/SemanticTextQuery目录下的官方示例展开,系统讲解 Windows 通用平台(UWP)中Windows.Data.Text.SemanticTextQuery系列 API 的三种典型用法:在整段字符串中定位匹配范围(Find)、按属性限定范围查找命中(FindInProperty)、以及从文件系统查询结果中提取属性级命中(GetMatchingPropertiesWithRanges)。读完本文,你将掌握如何在 JavaScript(WinJS)UWP 应用中编写 Advanced Query Syntax(AQS)查询、解析返回的文本范围(TextRange)并实现命中文本的高亮渲染,同时了解该示例在 Windows 10 环境下的构建、部署与运行流程。

示例定位与核心 API 总览

本示例来自 Windows 通用平台示例集(Windows-universal-samples),当前仓库中位于 archived/SemanticTextQuery 目录,官方定位为“Semantic text query sample”,用于演示如何借助语义文本查询 API,在字符串或文件属性中找出与查询相匹配的命中片段。其原始说明文档 README.md 明确了三个演示场景:

  • 使用SemanticTextQuery.Find方法,找出字符串中与 AQS 查询匹配的文本范围;
  • 使用SemanticTextQuery.FindInProperty方法,找出某个具体属性的值中与 AQS 查询匹配的文本范围;
  • 使用StorageFileQueryResult.GetMatchingPropertiesWithRanges方法,找出文件查询结果中被查询命中的所有属性及其对应范围。

当前归档目录中保留了完整的 JavaScript(WinJS)实现,项目文件结构如下:

archived/SemanticTextQuery/ ├── README.md # 示例说明文档 └── js/ ├── SemanticTextQuery.sln # Visual Studio 解决方案 ├── SemanticTextQuery.jsproj # JavaScript 项目文件 ├── Package.appxmanifest # 应用清单(声明 picturesLibrary 能力) ├── html/ │ ├── stringMatches.html # 场景一页面:Find │ ├── propertyMatches.html # 场景二页面:FindInProperty │ └── filePropertiesMatches.html # 场景三页面:GetMatchingPropertiesWithRanges └── js/ ├── stringMatches.js # 场景一逻辑 ├── propertyMatches.js # 场景二逻辑 ├── filePropertiesMatches.js # 场景三逻辑 └── sample-configuration.js # 场景导航与高亮辅助函数

从代码可以看出,示例依赖的 API 位于Windows.Data.Text命名空间(Windows.Data.Text.SemanticTextQuery),并结合Windows.Storage.Search的文件查询机制完成第三个场景。需要说明的是,README 中提及的 C++/C#/JavaScript 三语言布局,在当前仓库的归档目录内仅保留了 JavaScript 一种实现。

场景一:使用 Find 在整段文本中定位命中范围

第一个场景演示的是最基础的用法:给定一段文本和一个 AQS 查询,返回文本中所有命中子串的位置范围。页面 stringMatches.html 提供了一个查询输入框,默认查询为continent OR can OR rain,测试文本为:

Mount Rainier is on the North American Continent.

点击Find按钮后,由 stringMatches.js 中的find函数执行查询:

function find() { var output = document.getElementById("output"); var queryTextBox = document.getElementById("queryBox"); // Retrieve the query entered in the textbox var searchFilter = queryTextBox.value; var content = output.innerText; // Look for the matches in the content var mySemanticTextQuery = new Windows.Data.Text.SemanticTextQuery(searchFilter, "en-us"); var ranges = mySemanticTextQuery.find(content); var newString; // Make the matches bold if (ranges.size > 0) { newString = SdkSample.highlightString(content, ranges); } else { newString = content + "<br><br/> No matches were found for your query. Please search again."; } output.innerHTML = newString; }

几个关键点值得展开说明:

  • 构造函数:new Windows.Data.Text.SemanticTextQuery(searchFilter, "en-us")的第一个参数是 AQS 查询字符串;第二个参数是 BCP-47 语言标签,用于指定查询所依赖的语言环境。该参数可省略(参见场景二),省略时使用系统当前语言。
  • Find 的返回值:find(content)返回一个包含多个TextRange对象的集合。从辅助函数highlightString的使用方式(见下文)可知,每个TextRange暴露startPosition(起始位置)与length(长度)两个属性,恰好描述了命中子串在原字符串中的区间。查询结果为空时ranges.size为 0,示例会提示 “No matches were found”。
  • AQS 语法:示例默认查询continent OR can OR rain展示了 AQS 中的OR逻辑运算符——只要文本中包含其中任意词即视为命中;同理,AQS 还支持AND、NOT等运算符及属性限定符(见场景二、场景三的默认查询)。

场景二:使用 FindInProperty 在属性值中查找匹配

第二个场景演示FindInProperty:查询不仅包含关键字,还通过属性名:值的形式把匹配范围限定到特定属性。页面 propertyMatches.html 定义了一张三行数据表,分别承载三个属性的值:

属性名(规范名)属性值
System.TitleThese are good times
System.AuthorWalker
System.CommentThere are many good times to be had. Go for a walk among the trees.

页面默认查询为Title:Good OR Comment:Tree,即只关心Title属性中匹配 “Good”、或Comment属性中匹配 “Tree” 的文本。点击Find后由 propertyMatches.js 处理:

function find() { var searchFilter = queryBox.value; var properties = ["System.Title", "System.Author", "System.Comment"]; var mySemanticTextQuery = new Windows.Data.Text.SemanticTextQuery(searchFilter); // Look for the matches in the properties properties.forEach(function (propertyName) { var output = document.getElementById(propertyName); var content = output.innerText; var ranges = mySemanticTextQuery.findInProperty(content, propertyName); var highlightedString = SdkSample.highlightString(content, ranges); output.innerHTML = highlightedString; }); }

实现要点:

  • 此处构造SemanticTextQuery时未传语言参数,与前一个场景形成对照,说明语言标签是可选参数。
  • findInProperty(content, propertyName)接收两个参数:属性当前的值文本,以及属性的规范名(canonical name,如System.Title)。API 内部会结合查询中的属性限定符(如Title:)与传入的属性名,判断哪些命中与当前属性相关并返回对应的TextRange集合。
  • 示例对每个属性分别调用findInProperty并把结果写回对应单元格,实现“只高亮当前属性内命中的文字”的效果。若查询限定符指向的属性与传入属性不一致(例如查询Author:X而当前处理System.Title),该属性通常不会产生命中。

场景三:使用 GetMatchingPropertiesWithRanges 获取文件属性级命中

第三个场景把语义查询与文件系统搜索结合起来:对“图片库”发起带 AQS 过滤的文件查询,然后针对每个结果文件获取被命中的所有属性及范围。页面 filePropertiesMatches.html 的默认查询为a AND datemodified:>2/1/2013,展示了 AQS 对“内容关键字 + 日期属性比较”组合查询的写法。

核心逻辑位于 filePropertiesMatches.js 的searchOnPicturesLibraryAndDisplayResults函数:

function searchOnPicturesLibraryAndDisplayResults() { var outputDiv = document.getElementById("output"); var searchFilter = queryBox.value; if (searchFilter === "") { return; } // Create a new file query from the pictures library and apply the AQS filter var options = new Windows.Storage.Search.QueryOptions(Windows.Storage.Search.CommonFileQuery.orderBySearchRank, ["*"]); options.indexerOption = Windows.Storage.Search.IndexerOption.onlyUseIndexer; options.userSearchFilter = searchFilter; options.setPropertyPrefetch(Windows.Storage.FileProperties.PropertyPrefetchOptions.documentProperties, []); var fileQuery; Windows.Storage.KnownFolders.getFolderForUserAsync(null /* current user */, Windows.Storage.KnownFolderId.picturesLibrary) .then(function (picturesLibrary) { fileQuery = picturesLibrary.createFileQueryWithOptions(options); // Limit to 20 results. return fileQuery.getFilesAsync(0, 20); }).done(function (files) { if (files.size > 0) { var filesLabel = (files.size === 1) ? "file" : "files"; var output = "<b>" + SdkSample.highlightString(files.size + " " + filesLabel + " found") + "</b><br><br>"; // Print all the file names for the results and highlight any matches on the filename property files.forEach(function (file) { var searchHits = fileQuery.getMatchingPropertiesWithRanges(file); var newString = ""; // If one of the hits we found in on the filename we'll highlight the file name if (searchHits.hasKey("System.FileName")) { newString += SdkSample.highlightString(file.name, searchHits.lookup("System.FileName")); } else { newString += SdkSample.highlightString(file.name); } output += newString + "<br/><br/>"; }); outputDiv.innerHTML = output; } else { outputDiv.innerText = "There were no matching files in your Pictures library"; } }); }

该场景涉及的关键机制:

  • QueryOptions 配置:以CommonFileQuery.orderBySearchRank指定排序方式为“按搜索相关度排名”,文件类型过滤为["*"](全部文件);indexerOption = IndexerOption.onlyUseIndexer强制只使用系统索引器加速搜索;userSearchFilter承载 AQS 查询字符串;setPropertyPrefetch(documentProperties, [])让系统在返回文件时预取文档属性。
  • GetMatchingPropertiesWithRanges:对每个结果文件调用fileQuery.getMatchingPropertiesWithRanges(file),返回一个以属性规范名为键(如System.FileName)的映射,值为该属性对应的TextRange集合。示例通过searchHits.hasKey("System.FileName")判断文件名属性是否命中,再用lookup("System.FileName")取出范围并高亮文件名。
  • 能力声明:访问“图片库”必须在 Package.appxmanifest 中声明picturesLibrary能力(见该文件末尾的<Capabilities>节),否则运行时会被拒绝访问。

辅助实现:命中范围的高亮渲染与字符串安全

三个场景都复用了 sample-configuration.js 中定义的SdkSample.highlightString辅助函数,其职责是把TextRange集合转换为带<b>加粗标签的 HTML 字符串:

// Method used to add bold tags to matches on a string. function highlightString(originalString, rangesToHighlight) { var pointerPosition = 0; var newString = ""; if (rangesToHighlight && rangesToHighlight.size > 0) { var currentAfterPosition = 0; rangesToHighlight.forEach(function (textRange) { newString += sanitizeString(originalString.slice(pointerPosition, textRange.startPosition)); currentAfterPosition = textRange.startPosition + textRange.length; var temp = "<b>" + sanitizeString(originalString.slice(textRange.startPosition, currentAfterPosition)) + "</b>"; newString += temp; pointerPosition = currentAfterPosition; }); if (pointerPosition !== originalString.length) { newString += sanitizeString(originalString.slice(pointerPosition, originalString.length)); } } else { newString = sanitizeString(originalString); } return newString; }

该函数按startPosition顺序遍历命中区间:先追加命中之前的普通文本,再把startPosition到startPosition + length之间的子串用<b>包裹,最后拼接剩余尾部文本。配套的sanitizeString借助一个隐藏span元素的innerText/innerHTML往返转换实现 HTML 转义,避免原始文本中的特殊字符破坏页面结构——这也是把用户可输入的文本渲染为 HTML 时的必要安全措施。同一个文件还通过WinJS.Namespace.define("SdkSample", ...)暴露了sampleTitle与scenarios,驱动三个场景页面的导航框架(scenario 列表分别指向stringMatches.html、propertyMatches.html、filePropertiesMatches.html三个页面)。

系统要求与运行环境

按 README.md 的说明,该示例的运行环境要求如下:

  • 客户端(Client):Windows 10
  • 服务端(Server):Windows Server 2016 Technical Preview
  • 手机(Phone):Windows 10
  • 构建工具:需要 Visual Studio 2017

从 Package.appxmanifest 的清单信息可以进一步确认:应用面向Windows.Universal目标设备家族,MinVersion为10.0.10240.0(即 Windows 10 首个正式版本),MaxVersionTested为10.0.18362.0;页面采用 WinJS 控件体系(如win-textbox、win-button样式类与data-win-control标记),因此构建时依赖 WinJS 4.0 库(位于js/Microsoft.WinJS.4.0目录)。

构建、部署与运行

README 给出了标准的构建与运行流程,按以下步骤操作即可:

构建示例

  1. 若以 ZIP 方式下载整个示例集,务必解压完整归档,而不仅是包含目标示例的文件夹——示例依赖集合中共享的公共文件。
  2. 启动 Microsoft Visual Studio 2017,选择文件>打开>项目/解决方案。
  3. 在解压目录中进入 Samples 子文件夹,再进入本示例文件夹,选择对应语言子目录下的解决方案文件(.sln)双击打开。就当前仓库而言,归档目录下可直接打开 archived/SemanticTextQuery/js/SemanticTextQuery.sln。
  4. 按Ctrl+Shift+B,或选择生成>生成解决方案完成编译。

部署与运行

  • 仅部署:选择生成>部署解决方案;
  • 部署并运行:按F5或选择调试>开始调试以调试模式运行;若只想运行不调试,按Ctrl+F5或选择调试>开始执行(不调试)。

运行后依次进入三个场景页,分别输入 AQS 查询并点击Find,即可观察命中文本被加粗高亮的效果;第三个场景还会在“图片库”中按datemodified等属性过滤并展示命中的文件列表。

小结

SemanticTextQuery系列 API 的价值在于把 AQS 查询解析与文本定位能力封装成可直接消费的“范围集合”,开发者无需自行实现分词、大小写与语义归一化等底层逻辑。本示例用三个由浅入深的场景完整覆盖了其核心能力:Find面向自由文本、FindInProperty面向带属性限定的查询、GetMatchingPropertiesWithRanges面向文件系统搜索结果,可作为在 UWP 应用中实现“搜索即高亮”、“搜索即定位”交互的参考模板。若要进一步研究实现细节,可对照阅读 archived/SemanticTextQuery 目录下的四个 JavaScript 源文件与三个 HTML 页面,并结合仓库中其他基于Windows.Storage.Search的示例(如 archived/FileSearch)理解文件查询机制的更多用法。

  • 示例工程

【免费下载链接】Windows-universal-samples

API samples for the Universal Windows Platform.

项目地址:https://gitcode.com/gh_mirrors/wi/Windows-universal-samples
点击查看免费下载
上一篇:Android虚拟定位终极指南:无需Root的应用级位置伪装解决方案
下一篇:Android虚拟定位终极指南:无需Root的应用级位置伪装完整方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询