5

我试图在 go 中反转一个字符串,但我在处理字符时遇到了麻烦。与 C 不同,GO 将字符串视为字节向量,而不是字符,这里称为符文。我试图做一些类型转换来做分配,但到目前为止我做不到。

这里的想法是生成 5 个大小为 100、200、300、400 和 500 的随机字符的字符串,然后反转它们的字符。我能够轻松地使 C 工作,但在 GO 中,语言返回一个错误,指出无法执行分配。

 func inverte() {
    var c = "A"
    var strs, aux string

    rand.Seed(time.Now().UnixNano())
    // Gera 5 vetores de 100, 200, 300, 400, e 500 caracteres
    for i := 1; i < 6; i++ {
        strs = randomString(i * 100)
        fmt.Print(strs)

        for i2, j := 0, len(strs); i2 < j; i2, j = i+1, j-1 {
           aux = strs[i2]
           strs[i2] = strs[j]
           strs[j] = aux
       }
   }
}
4

2 回答 2

7

如果您想考虑unicode 组合字符(旨在修改其他字符的字符,例如重音´+ e= é),Andrew Sellers对此要点有一个有趣的看法。

它首先列出所有组合变音符号 (CDM)Unicode 块范围(包含最常见组合字符的Unicode 块

  • 常客继承),所以通常的◌̀ ◌́ ◌̂ ◌̃ ◌̄ ◌̅ ◌̆ ◌̇ ◌̈, ...;
  • 扩展(包含德语方言中使用的变音符号 - Teuthonista
  • 补充(或乌拉尔音标、中世纪符号和德国方言——同样,Teuthonista)
  • 用于符号(用于修改符号字符的箭头、圆点、外壳和覆盖)
  • 半标记(用于跨越多个字符的变音符号部分,如此处所示
var combining = &unicode.RangeTable{
    R16: []unicode.Range16{
        {0x0300, 0x036f, 1}, // combining diacritical marks
        {0x1ab0, 0x1aff, 1}, // combining diacritical marks extended
        {0x1dc0, 0x1dff, 1}, // combining diacritical marks supplement
        {0x20d0, 0x20ff, 1}, // combining diacritical marks for symbols
        {0xfe20, 0xfe2f, 1}, // combining half marks
    },
}

然后,您可以在符文之后读取初始字符串:

sv := []rune(s)

但是如果你以相反的顺序这样做,你会首先遇到组合变音符号(CDM)而那些需要保持它们的顺序,被颠倒

for ix := len(sv) - 1; ix >= 0; ix-- {
        r := sv[ix]
        if unicode.In(r, combining) {
            cv = append(cv, r)
            fmt.Printf("Detect combining diacritical mark ' %c'\n", r)
        }

%c(注意组合符文周围的空格:'%c'没有空格意味着将标记与第一个'ͤ':而不是'ͤ'结合起来。我尝试使用CGJ Combining Grapheme Joiner \u034F,但这不起作用)

如果最终遇到常规符文,则需要与这些 CDM 结合,然后将其添加到反向最终符文数组中。

        } else {
            rrv := make([]rune, 0, len(cv)+1)
            rrv = append(rrv, r)
            rrv = append(rrv, cv...)
            fmt.Printf("regular mark '%c' (with '%d' combining diacritical marks '%s') => '%s'\n", r, len(cv), string(cv), string(rrv))
            rv = append(rv, rrv...)
            cv = make([]rune, 0)
        }

更复杂的地方是表情符号,例如最近的修饰符,如中深肤色,菲茨帕特里克肤色等级中的第 5 类。
如果忽略,反向 '‍‍⚖️' 将给出 '️⚖‍‍',失去最后两个表情符号的肤色。

不要让我开始使用零宽度连接器( 200D),它从 开始Wisdom/Awesome-Unicode强制将相邻字符连接在一起(例如,阿拉伯字符或支持的表情符号)。它可以用来组成顺序组合的表情符号。

以下是组合表情符号的两个示例,其内部元素顺序在“反转”时应保持相同顺序:

‍单独是(从Unicode到代码点转换器):

这些应该保持完全相同的顺序。

字符”“法官”(意为“法官”语义值的抽象概念)可以用几个字形或一个字形来表示。

‍⚖️实际上是一个组合字形(这里由两个表情符号组成),代表法官。该顺序不应颠倒
下面的程序正确地检测到“零宽度连接器”并且反转它组合的表情符号。
如果您检查该表情符号,您会发现它由以下部分组成:

同样,需要保留该序列顺序。

注意:实际评委表情 ‍⚖️</a> 使用的是MAN (1F468),而不是Adult (1F9D1)(加上上面列出的其他字符:深色皮肤、ZWJ、比例),因此表示为一个字形,而不是一簇字素

含义:单个字形,“法官”的官方表情符号,需要将“man”与“scale”组合(产生一个字形‍⚖️)而不是“adult”+“scale”。
后者,“成人”+“比例”,仍然被认为是“一个字符”:你不能只选择比例,因为 ZWJ(零宽度连接器)。但是那个“字符”被表示为一个组合字形‍⚖️,两个字形,每个字形通过代码点+字体
具体书面表示一个对应的字形)

显然,使用第一个组合(“man”+“scale”)会产生更具表现力的角色 ‍⚖️。

见“文字表示的字素与抽象字符的关系

字形和正字形字符是相当具体的对象,因为普通用户(非专家)熟悉它们,通常从他们第一次学习“ABC”(或从他们的写作中等效)开始就被教导使用它们系统,当然)。

然而,在信息系统领域,我们对字符有不同的理解:抽象字符是给定系统中文本表示的最小单位
实际上,这些在两个重要的意义上是抽象的:

  • 首先,这些抽象字符中的一些可能不对应于正字法中的任何具体字符,正如我们在上面的水平选项卡中看到的那样。
  • 其次,具体的书写对象(字形和正字形)可以用一种以上的抽象字符表示,而不一定是一对一的,正如我们在上面“ô”表示的情况下看到的那样。通过一个序列<O, CIRCUMFLEX>。

然后:“从字形到代码点再到字形”:

https://scripts.sil.org/cms/scripts/render_graphic.php?&type=media_graphic&filename=../sites/nrsi/media/IWS-CharacterIntervene.png&image_type=png&width=648&height=421

  • 字素是用户通常习惯于思考的单位。
  • 然而,在计算机内部,过程是根据字符来完成的。

我们不会在字形和字形之间建立任何直接联系。
正如我们在这里定义的这两个概念一样,它们之间没有直接的联系。它们只能通过抽象字符间接关联。
这是一个要掌握的关键点:抽象字符是其他元素相关的共同元素。


Go Playground中的完整示例。

Reverse 'Hello, World' => 'dlroW ,olleH'
Reverse '⃠' => '⃠'
Reverse '‍‍⚖️' => '‍⚖️‍'
Reverse 'aͤoͧiͤ  š́ž́ʟ́' => 'ʟ́ž́š́  iͤoͧaͤ'
Reverse 'H̙̖ell͔o̙̟͚͎̗̹̬ ̯W̖͝ǫ̬̞̜rḷ̦̣̪d̰̲̗͈' => 'd̰̲̗͈ḷ̦̣̪rǫ̬̞̜W̖͝ ̯o̙̟͚͎̗̹̬l͔leH̙̖'
于 2020-07-05T16:11:24.810 回答
3

正如您正确识别的那样,go 字符串是不可变的,因此您不能在给定索引处分配符文/字符值。

而不是原地反转字符串,而是必须在字符串中创建符文的副本并反转它们,然后返回结果字符串。

例如(去游乐场):

func reverse(s string) string {
  rs := []rune(s)
  for i, j := 0, len(rs)-1; i < j; i, j = i+1, j-1 {
    rs[i], rs[j] = rs[j], rs[i]
  }
  return string(rs)
}

func main() {
  fmt.Println(reverse("Hello, World!"))
  // !dlroW ,olleH
  fmt.Println(reverse("Hello, 世界!"))
  // !界世 ,olleH
}

由于 Unicode 的复杂性(例如组合变音符号),这种方法存在一些问题,但这会让你开始。

于 2018-11-11T00:45:53.743 回答